Merge "Load binary hyphen data files"
diff --git a/Android.mk b/Android.mk
index f1e16b8..9029f4e 100644
--- a/Android.mk
+++ b/Android.mk
@@ -483,6 +483,7 @@
 	frameworks/base/wifi/java/android/net/wifi/p2p/nsd/WifiP2pServiceInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WpsInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/ScanResult.aidl \
+        frameworks/base/wifi/java/android/net/wifi/ScanInfo.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WifiEnterpriseConfig.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WifiConfiguration.aidl \
 	frameworks/base/wifi/java/android/net/wifi/WifiInfo.aidl \
diff --git a/api/current.txt b/api/current.txt
index c6f349f..e3c9366 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -414,6 +414,7 @@
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contextClickable = 16844007; // 0x10104e7
+    field public static final int contextPopupMenuStyle = 16844032; // 0x1010500
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1220,6 +1221,7 @@
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
+    field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
     field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
     field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -4014,6 +4016,23 @@
     field public java.lang.String serviceDetails;
   }
 
+  public class AutomaticZenRule implements android.os.Parcelable {
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+    ctor public AutomaticZenRule(android.os.Parcel);
+    method public int describeContents();
+    method public android.net.Uri getConditionId();
+    method public int getInterruptionFilter();
+    method public java.lang.String getName();
+    method public android.content.ComponentName getOwner();
+    method public boolean isEnabled();
+    method public void setConditionId(android.net.Uri);
+    method public void setEnabled(boolean);
+    method public void setInterruptionFilter(int);
+    method public void setName(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
+  }
+
   public class DatePickerDialog extends android.app.AlertDialog implements android.widget.DatePicker.OnDateChangedListener android.content.DialogInterface.OnClickListener {
     ctor public DatePickerDialog(android.content.Context, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
     ctor public DatePickerDialog(android.content.Context, int, android.app.DatePickerDialog.OnDateSetListener, int, int, int);
@@ -5059,15 +5078,20 @@
   }
 
   public class NotificationManager {
+    method public boolean addOrUpdateAutomaticZenRule(android.app.AutomaticZenRule);
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
+    method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
+    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
     method public void notify(java.lang.String, int, android.app.Notification);
+    method public boolean removeAutomaticZenRule(java.lang.String);
+    method public boolean renameAutomaticZenRule(java.lang.String, java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
@@ -18131,6 +18155,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
+    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
     method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
@@ -18142,6 +18167,11 @@
     method public final java.lang.String getVersion();
   }
 
+  public class MtpEvent {
+    ctor public MtpEvent();
+    method public int getEventCode();
+  }
+
   public final class MtpObjectInfo {
     method public final int getAssociationDesc();
     method public final int getAssociationType();
@@ -18251,6 +18281,7 @@
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+    field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
@@ -19157,6 +19188,22 @@
 
 package android.net.wifi {
 
+  public class ScanInfo implements android.os.Parcelable {
+    ctor public ScanInfo(android.net.wifi.ScanResult);
+    ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int);
+    method public int describeContents();
+    method public long getBssid();
+    method public byte[] getIconData();
+    method public java.lang.String getIconType();
+    method public java.lang.String getName();
+    method public int getOsuIdentity();
+    method public int getRssi();
+    method public android.net.wifi.ScanResult getScanResult();
+    method public java.lang.String getServiceDescription();
+    method public java.lang.String getSsid();
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
     method public boolean is80211mcResponder();
@@ -19357,6 +19404,7 @@
     method public java.util.List<android.net.wifi.WifiConfiguration> getConfiguredNetworks();
     method public android.net.wifi.WifiInfo getConnectionInfo();
     method public android.net.DhcpInfo getDhcpInfo();
+    method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -19372,6 +19420,7 @@
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
+    method public void setOsuSelection(int);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -23540,7 +23589,7 @@
     method public static final int myPid();
     method public static final int myTid();
     method public static final int myUid();
-    method public static final android.os.UserHandle myUserHandle();
+    method public static android.os.UserHandle myUserHandle();
     method public static final void sendSignal(int, int);
     method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -36522,6 +36571,7 @@
     method public void setY(float);
     method public void setZ(float);
     method public boolean showContextMenu();
+    method public boolean showContextMenu(float, float);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startAnimation(android.view.animation.Animation);
@@ -36988,6 +37038,7 @@
     method public void setTransitionGroup(boolean);
     method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
+    method public boolean showContextMenuForChild(android.view.View, float, float);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
     method public void startLayoutAnimation();
@@ -37109,6 +37160,7 @@
     method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public abstract void requestTransparentRegion(android.view.View);
     method public abstract boolean showContextMenuForChild(android.view.View);
+    method public abstract boolean showContextMenuForChild(android.view.View, float, float);
     method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
     method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
   }
@@ -40887,6 +40939,7 @@
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
     method public int getMaxAvailableHeight(android.view.View, int);
+    method public int getMaxAvailableHeight(android.view.View, int, boolean);
     method public boolean getOverlapAnchor();
     method public int getSoftInputMode();
     method public int getWidth();
@@ -45330,7 +45383,10 @@
   }
 
   public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
     method public java.lang.reflect.Type[] getGenericExceptionTypes();
@@ -45340,6 +45396,7 @@
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
@@ -45413,7 +45470,10 @@
   }
 
   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
@@ -45427,6 +45487,7 @@
     method public java.lang.Class<?> getReturnType();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
diff --git a/api/system-current.txt b/api/system-current.txt
index c7e82cd..b1590d8 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -506,6 +506,7 @@
     field public static final int contentInsetRight = 16843862; // 0x1010456
     field public static final int contentInsetStart = 16843859; // 0x1010453
     field public static final int contextClickable = 16844007; // 0x10104e7
+    field public static final int contextPopupMenuStyle = 16844032; // 0x1010500
     field public static final int controlX1 = 16843772; // 0x10103fc
     field public static final int controlX2 = 16843774; // 0x10103fe
     field public static final int controlY1 = 16843773; // 0x10103fd
@@ -1316,6 +1317,7 @@
     field public static final int textAppearanceListItemSmall = 16843679; // 0x101039f
     field public static final int textAppearanceMedium = 16842817; // 0x1010041
     field public static final int textAppearanceMediumInverse = 16842820; // 0x1010044
+    field public static final int textAppearancePopupMenuHeader = 16844033; // 0x1010501
     field public static final int textAppearanceSearchResultSubtitle = 16843424; // 0x10102a0
     field public static final int textAppearanceSearchResultTitle = 16843425; // 0x10102a1
     field public static final int textAppearanceSmall = 16842818; // 0x1010042
@@ -4125,6 +4127,23 @@
     field public java.lang.String serviceDetails;
   }
 
+  public class AutomaticZenRule implements android.os.Parcelable {
+    ctor public AutomaticZenRule(java.lang.String, android.content.ComponentName, android.net.Uri, int, boolean);
+    ctor public AutomaticZenRule(android.os.Parcel);
+    method public int describeContents();
+    method public android.net.Uri getConditionId();
+    method public int getInterruptionFilter();
+    method public java.lang.String getName();
+    method public android.content.ComponentName getOwner();
+    method public boolean isEnabled();
+    method public void setConditionId(android.net.Uri);
+    method public void setEnabled(boolean);
+    method public void setInterruptionFilter(int);
+    method public void setName(java.lang.String);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.app.AutomaticZenRule> CREATOR;
+  }
+
   public class BroadcastOptions {
     method public static android.app.BroadcastOptions makeBasic();
     method public void setTemporaryAppWhitelistDuration(long);
@@ -5176,15 +5195,20 @@
   }
 
   public class NotificationManager {
+    method public boolean addOrUpdateAutomaticZenRule(android.app.AutomaticZenRule);
     method public void cancel(int);
     method public void cancel(java.lang.String, int);
     method public void cancelAll();
     method public android.service.notification.StatusBarNotification[] getActiveNotifications();
+    method public android.app.AutomaticZenRule getAutomaticZenRule(java.lang.String);
+    method public java.util.List<android.app.AutomaticZenRule> getAutomaticZenRules();
     method public final int getCurrentInterruptionFilter();
     method public android.app.NotificationManager.Policy getNotificationPolicy();
     method public boolean isNotificationPolicyAccessGranted();
     method public void notify(int, android.app.Notification);
     method public void notify(java.lang.String, int, android.app.Notification);
+    method public boolean removeAutomaticZenRule(java.lang.String);
+    method public boolean renameAutomaticZenRule(java.lang.String, java.lang.String);
     method public final void setInterruptionFilter(int);
     method public void setNotificationPolicy(android.app.NotificationManager.Policy);
     field public static final java.lang.String ACTION_INTERRUPTION_FILTER_CHANGED = "android.app.action.INTERRUPTION_FILTER_CHANGED";
@@ -19643,6 +19667,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
+    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
     method public boolean sendObject(int, int, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
@@ -19654,6 +19679,11 @@
     method public final java.lang.String getVersion();
   }
 
+  public class MtpEvent {
+    ctor public MtpEvent();
+    method public int getEventCode();
+  }
+
   public final class MtpObjectInfo {
     method public final int getAssociationDesc();
     method public final int getAssociationType();
@@ -19763,6 +19793,7 @@
     field public static final java.lang.String CONNECTIVITY_ACTION = "android.net.conn.CONNECTIVITY_CHANGE";
     field public static final deprecated int DEFAULT_NETWORK_PREFERENCE = 1; // 0x1
     field public static final java.lang.String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+    field public static final java.lang.String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
     field public static final java.lang.String EXTRA_EXTRA_INFO = "extraInfo";
     field public static final java.lang.String EXTRA_IS_FAILOVER = "isFailover";
     field public static final java.lang.String EXTRA_NETWORK = "android.net.extra.NETWORK";
@@ -20910,6 +20941,22 @@
     field public byte id;
   }
 
+  public class ScanInfo implements android.os.Parcelable {
+    ctor public ScanInfo(android.net.wifi.ScanResult);
+    ctor public ScanInfo(long, int, java.lang.String, java.lang.String, java.lang.String, java.lang.String, byte[], int);
+    method public int describeContents();
+    method public long getBssid();
+    method public byte[] getIconData();
+    method public java.lang.String getIconType();
+    method public java.lang.String getName();
+    method public int getOsuIdentity();
+    method public int getRssi();
+    method public android.net.wifi.ScanResult getScanResult();
+    method public java.lang.String getServiceDescription();
+    method public java.lang.String getSsid();
+    method public void writeToParcel(android.os.Parcel, int);
+  }
+
   public class ScanResult implements android.os.Parcelable {
     method public int describeContents();
     method public boolean is80211mcResponder();
@@ -21135,6 +21182,7 @@
     method public android.net.wifi.WifiConnectionStatistics getConnectionStatistics();
     method public android.net.DhcpInfo getDhcpInfo();
     method public java.util.List<android.net.wifi.WifiConfiguration> getPrivilegedConfiguredNetworks();
+    method public java.util.List<android.net.wifi.ScanInfo> getScanInfos();
     method public java.util.List<android.net.wifi.ScanResult> getScanResults();
     method public int getWifiState();
     method public boolean is5GHzBandSupported();
@@ -21154,6 +21202,7 @@
     method public boolean reconnect();
     method public boolean removeNetwork(int);
     method public boolean saveConfiguration();
+    method public void setOsuSelection(int);
     method public void setTdlsEnabled(java.net.InetAddress, boolean);
     method public void setTdlsEnabledWithMacAddress(java.lang.String, boolean);
     method public boolean setWifiEnabled(boolean);
@@ -25492,7 +25541,7 @@
     method public static final int myPid();
     method public static final int myTid();
     method public static final int myUid();
-    method public static final android.os.UserHandle myUserHandle();
+    method public static android.os.UserHandle myUserHandle();
     method public static final void sendSignal(int, int);
     method public static final void setThreadPriority(int, int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
     method public static final void setThreadPriority(int) throws java.lang.IllegalArgumentException, java.lang.SecurityException;
@@ -25668,8 +25717,8 @@
     ctor public UserHandle(android.os.Parcel);
     method public int describeContents();
     method public int getIdentifier();
-    method public final boolean isOwner();
-    method public static final int myUserId();
+    method public boolean isOwner();
+    method public static int myUserId();
     method public static android.os.UserHandle readFromParcel(android.os.Parcel);
     method public void writeToParcel(android.os.Parcel, int);
     method public static void writeToParcel(android.os.UserHandle, android.os.Parcel);
@@ -32843,6 +32892,7 @@
     field public static final java.lang.String ACTION_DEFAULT_DIALER_CHANGED = "android.telecom.action.DEFAULT_DIALER_CHANGED";
     field public static final java.lang.String ACTION_INCOMING_CALL = "android.telecom.action.INCOMING_CALL";
     field public static final java.lang.String ACTION_PHONE_ACCOUNT_REGISTERED = "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
+    field public static final java.lang.String ACTION_PHONE_ACCOUNT_UNREGISTERED = "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
     field public static final java.lang.String ACTION_SHOW_CALL_ACCESSIBILITY_SETTINGS = "android.telecom.action.SHOW_CALL_ACCESSIBILITY_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
     field public static final java.lang.String ACTION_SHOW_MISSED_CALLS_NOTIFICATION = "android.telecom.action.SHOW_MISSED_CALLS_NOTIFICATION";
@@ -38816,6 +38866,7 @@
     method public void setY(float);
     method public void setZ(float);
     method public boolean showContextMenu();
+    method public boolean showContextMenu(float, float);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback);
     method public android.view.ActionMode startActionMode(android.view.ActionMode.Callback, int);
     method public void startAnimation(android.view.animation.Animation);
@@ -39282,6 +39333,7 @@
     method public void setTransitionGroup(boolean);
     method public boolean shouldDelayChildPressedState();
     method public boolean showContextMenuForChild(android.view.View);
+    method public boolean showContextMenuForChild(android.view.View, float, float);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
     method public android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
     method public void startLayoutAnimation();
@@ -39403,6 +39455,7 @@
     method public abstract boolean requestSendAccessibilityEvent(android.view.View, android.view.accessibility.AccessibilityEvent);
     method public abstract void requestTransparentRegion(android.view.View);
     method public abstract boolean showContextMenuForChild(android.view.View);
+    method public abstract boolean showContextMenuForChild(android.view.View, float, float);
     method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback);
     method public abstract android.view.ActionMode startActionModeForChild(android.view.View, android.view.ActionMode.Callback, int);
   }
@@ -43495,6 +43548,7 @@
     method public int getInputMethodMode();
     method public int getMaxAvailableHeight(android.view.View);
     method public int getMaxAvailableHeight(android.view.View, int);
+    method public int getMaxAvailableHeight(android.view.View, int, boolean);
     method public boolean getOverlapAnchor();
     method public int getSoftInputMode();
     method public int getWidth();
@@ -47938,7 +47992,10 @@
   }
 
   public final class Constructor extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<T> getDeclaringClass();
     method public java.lang.Class<?>[] getExceptionTypes();
     method public java.lang.reflect.Type[] getGenericExceptionTypes();
@@ -47948,6 +48005,7 @@
     method public java.lang.annotation.Annotation[][] getParameterAnnotations();
     method public java.lang.Class<?>[] getParameterTypes();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Constructor<T>>[] getTypeParameters();
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isSynthetic();
     method public boolean isVarArgs();
     method public T newInstance(java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.InstantiationException, java.lang.reflect.InvocationTargetException;
@@ -48021,7 +48079,10 @@
   }
 
   public final class Method extends java.lang.reflect.AccessibleObject implements java.lang.reflect.GenericDeclaration java.lang.reflect.Member {
+    method public boolean equals(java.lang.Object);
     method public A getAnnotation(java.lang.Class<A>);
+    method public java.lang.annotation.Annotation[] getAnnotations();
+    method public java.lang.annotation.Annotation[] getDeclaredAnnotations();
     method public java.lang.Class<?> getDeclaringClass();
     method public java.lang.Object getDefaultValue();
     method public java.lang.Class<?>[] getExceptionTypes();
@@ -48035,6 +48096,7 @@
     method public java.lang.Class<?> getReturnType();
     method public java.lang.reflect.TypeVariable<java.lang.reflect.Method>[] getTypeParameters();
     method public java.lang.Object invoke(java.lang.Object, java.lang.Object...) throws java.lang.IllegalAccessException, java.lang.IllegalArgumentException, java.lang.reflect.InvocationTargetException;
+    method public boolean isAnnotationPresent(java.lang.Class<? extends java.lang.annotation.Annotation>);
     method public boolean isBridge();
     method public boolean isSynthetic();
     method public boolean isVarArgs();
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 20ac8d8..5c9fd51 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -163,6 +163,7 @@
                 "       am task drag-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
                 "       am task size-task-test <TASK_ID> <STEP_SIZE> [DELAY_MS] \n" +
                 "       am get-config\n" +
+                "       am suppress-resize-config-changes <true|false>\n" +
                 "       am set-inactive [--user <USER_ID>] <PACKAGE> true|false\n" +
                 "       am get-inactive [--user <USER_ID>] <PACKAGE>\n" +
                 "       am send-trim-memory [--user <USER_ID>] <PROCESS>\n" +
@@ -326,6 +327,8 @@
                 "\n" +
                 "am get-config: retrieve the configuration and any recent configurations\n" +
                 "  of the device.\n" +
+                "am suppress-resize-config-changes: suppresses configuration changes due to\n" +
+                "  user resizing an activity/task.\n" +
                 "\n" +
                 "am set-inactive: sets the inactive state of an app.\n" +
                 "\n" +
@@ -453,6 +456,8 @@
             runTask();
         } else if (op.equals("get-config")) {
             runGetConfig();
+        } else if (op.equals("suppress-resize-config-changes")) {
+            runSuppressResizeConfigChanges();
         } else if (op.equals("set-inactive")) {
             runSetInactive();
         } else if (op.equals("get-inactive")) {
@@ -2606,6 +2611,16 @@
         }
     }
 
+    private void runSuppressResizeConfigChanges() throws Exception {
+        boolean suppress = Boolean.valueOf(nextArgRequired());
+
+        try {
+            mAm.suppressResizeConfigChanges(suppress);
+        } catch (RemoteException e) {
+            System.err.println("Error suppressing resize config changes: " + e);
+        }
+    }
+
     private void runSetInactive() throws Exception {
         int userId = UserHandle.USER_CURRENT;
 
diff --git a/cmds/pm/src/com/android/commands/pm/Pm.java b/cmds/pm/src/com/android/commands/pm/Pm.java
index 3f0a444..ebf5085 100644
--- a/cmds/pm/src/com/android/commands/pm/Pm.java
+++ b/cmds/pm/src/com/android/commands/pm/Pm.java
@@ -22,11 +22,13 @@
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_ALWAYS_ASK;
 import static android.content.pm.PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_NEVER;
 
+import android.accounts.IAccountManager;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.app.PackageInstallObserver;
 import android.content.ComponentName;
+import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.IIntentSender;
 import android.content.Intent;
@@ -92,6 +94,7 @@
     IPackageManager mPm;
     IPackageInstaller mInstaller;
     IUserManager mUm;
+    IAccountManager mAm;
 
     private WeakHashMap<String, Resources> mResourceCache
             = new WeakHashMap<String, Resources>();
@@ -122,9 +125,10 @@
         if (args.length < 1) {
             return showUsage();
         }
-
-        mUm = IUserManager.Stub.asInterface(ServiceManager.getService("user"));
+        mAm = IAccountManager.Stub.asInterface(ServiceManager.getService(Context.ACCOUNT_SERVICE));
+        mUm = IUserManager.Stub.asInterface(ServiceManager.getService(Context.USER_SERVICE));
         mPm = IPackageManager.Stub.asInterface(ServiceManager.getService("package"));
+
         if (mPm == null) {
             System.err.println(PM_NOT_RUNNING_ERR);
             return 1;
@@ -1381,6 +1385,8 @@
                 }
             } else if ("--managed".equals(opt)) {
                 flags |= UserInfo.FLAG_MANAGED_PROFILE;
+            } else if ("--restricted".equals(opt)) {
+                flags |= UserInfo.FLAG_RESTRICTED;
             } else {
                 System.err.println("Error: unknown option " + opt);
                 showUsage();
@@ -1394,12 +1400,18 @@
         }
         name = arg;
         try {
-            UserInfo info = null;
-            if (userId < 0) {
+            UserInfo info;
+            if ((flags & UserInfo.FLAG_RESTRICTED) != 0) {
+                // In non-split user mode, userId can only be SYSTEM
+                int parentUserId = userId >= 0 ? userId : UserHandle.USER_SYSTEM;
+                info = mUm.createRestrictedProfile(name, parentUserId);
+                mAm.addSharedAccountsFromParentUser(userId, parentUserId);
+            } else if (userId < 0) {
                 info = mUm.createUser(name, flags);
             } else {
                 info = mUm.createProfileForUser(name, flags, userId);
             }
+
             if (info != null) {
                 System.out.println("Success: created user id " + info.id);
                 return 1;
@@ -2122,7 +2134,7 @@
         System.err.println("       pm get-install-location");
         System.err.println("       pm set-permission-enforced PERMISSION [true|false]");
         System.err.println("       pm trim-caches DESIRED_FREE_SPACE [internal|UUID]");
-        System.err.println("       pm create-user [--profileOf USER_ID] [--managed] USER_NAME");
+        System.err.println("       pm create-user [--profileOf USER_ID] [--managed] [--restricted] USER_NAME");
         System.err.println("       pm remove-user USER_ID");
         System.err.println("       pm get-max-users");
         System.err.println("");
diff --git a/core/java/android/accounts/AccountManager.java b/core/java/android/accounts/AccountManager.java
index d751f96f..0a7568a 100644
--- a/core/java/android/accounts/AccountManager.java
+++ b/core/java/android/accounts/AccountManager.java
@@ -16,6 +16,7 @@
 
 package android.accounts;
 
+import android.annotation.NonNull;
 import android.annotation.RequiresPermission;
 import android.annotation.Size;
 import android.app.Activity;
@@ -423,6 +424,7 @@
      * @return An array of {@link Account}, one for each account.  Empty
      *     (never null) if no accounts have been added.
      */
+    @NonNull
     @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccounts() {
         try {
@@ -448,6 +450,7 @@
      * @return An array of {@link Account}, one for each account.  Empty
      *     (never null) if no accounts have been added.
      */
+    @NonNull
     @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsAsUser(int userId) {
         try {
@@ -466,6 +469,7 @@
      * @param uid the uid of the calling app.
      * @return the accounts that are available to this package and user.
      */
+    @NonNull
     public Account[] getAccountsForPackage(String packageName, int uid) {
         try {
             return mService.getAccountsForPackage(packageName, uid, mContext.getOpPackageName());
@@ -483,6 +487,7 @@
      * @return An array of {@link Account}, one per matching account.  Empty
      *     (never null) if no accounts of the specified type have been added.
      */
+    @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName) {
         try {
             return mService.getAccountsByTypeForPackage(type, packageName,
@@ -515,12 +520,14 @@
      * @return An array of {@link Account}, one per matching account.  Empty
      *     (never null) if no accounts of the specified type have been added.
      */
+    @NonNull
     @RequiresPermission(GET_ACCOUNTS)
     public Account[] getAccountsByType(String type) {
         return getAccountsByTypeAsUser(type, Process.myUserHandle());
     }
 
     /** @hide Same as {@link #getAccountsByType(String)} but for a specific user. */
+    @NonNull
     public Account[] getAccountsByTypeAsUser(String type, UserHandle userHandle) {
         try {
             return mService.getAccountsAsUser(type, userHandle.getIdentifier(),
@@ -1537,23 +1544,22 @@
         }.start();
     }
 
+
     /**
-     * Adds a shared account from the primary user to a secondary user. Adding the shared account
+     * Adds shared accounts from a parent user to a secondary user. Adding the shared account
      * doesn't take effect immediately. When the target user starts up, any pending shared accounts
      * are attempted to be copied to the target user from the primary via calls to the
      * authenticator.
-     * @param account the account to share
-     * @param user the target user
-     * @return
+     * @param parentUser parent user
+     * @param user target user
      * @hide
      */
-    public boolean addSharedAccount(final Account account, UserHandle user) {
+    public void addSharedAccountsFromParentUser(UserHandle parentUser, UserHandle user) {
         try {
-            boolean val = mService.addSharedAccountAsUser(account, user.getIdentifier());
-            return val;
+            mService.addSharedAccountsFromParentUser(parentUser.getIdentifier(),
+                    user.getIdentifier());
         } catch (RemoteException re) {
-            // won't ever happen
-            throw new RuntimeException(re);
+            throw new IllegalStateException(re);
         }
     }
 
diff --git a/core/java/android/accounts/IAccountManager.aidl b/core/java/android/accounts/IAccountManager.aidl
index 4378df4..0d95db1 100644
--- a/core/java/android/accounts/IAccountManager.aidl
+++ b/core/java/android/accounts/IAccountManager.aidl
@@ -74,9 +74,9 @@
         String authTokenType);
 
     /* Shared accounts */
-    boolean addSharedAccountAsUser(in Account account, int userId);
     Account[] getSharedAccountsAsUser(int userId);
     boolean removeSharedAccountAsUser(in Account account, int userId);
+    void addSharedAccountsFromParentUser(int parentUserId, int userId);
 
     /* Account renaming. */
     void renameAccount(in IAccountManagerResponse response, in Account accountToRename, String newName);
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 4997dc7..f60250c 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -3742,6 +3742,12 @@
     }
 
     @Override
+    public void setTheme(int resid) {
+        super.setTheme(resid);
+        mWindow.setTheme(resid);
+    }
+
+    @Override
     protected void onApplyThemeResource(Resources.Theme theme, @StyleRes int resid,
             boolean first) {
         if (mParent == null) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 4191dce..6606f9b 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -478,18 +478,26 @@
 
     /**
      * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
+     * that the resize is from the window manager (instead of the user) due to a screen
+     * rotation change.
+     * @hide
+     */
+    public static final int RESIZE_MODE_SYSTEM_SCREEN_ROTATION = 1;
+
+    /**
+     * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
      * that the resize is initiated by the user (most likely via a drag action on the
      * window's edge or corner).
      * @hide
      */
-    public static final int RESIZE_MODE_USER   = 1;
+    public static final int RESIZE_MODE_USER   = 2;
 
     /**
      * Input parameter to {@link android.app.IActivityManager#resizeTask} which indicates
      * that the resize should be performed even if the bounds appears unchanged.
      * @hide
      */
-    public static final int RESIZE_MODE_FORCED = 2;
+    public static final int RESIZE_MODE_FORCED = 3;
 
     /** @hide */
     public int getFrontActivityScreenCompatMode() {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3864a4bb..cb1a89f 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2682,6 +2682,13 @@
             reportSizeConfigurations(token, horizontal, vertical);
             return true;
         }
+        case SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final boolean suppress = data.readInt() == 1;
+            suppressResizeConfigChanges(suppress);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -6216,5 +6223,17 @@
         reply.recycle();
     }
 
+    @Override
+    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeInt(suppress ? 1 : 0);
+        mRemote.transact(SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/ActivityView.java b/core/java/android/app/ActivityView.java
index 9c0d931..371c923 100644
--- a/core/java/android/app/ActivityView.java
+++ b/core/java/android/app/ActivityView.java
@@ -239,6 +239,8 @@
         }
 
         mTextureView.setSurfaceTextureListener(null);
+
+        mThread.quit();
     }
 
     private void attachToSurfaceWhenReady() {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 5544a71..f29dba2 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -126,8 +126,14 @@
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags)
             throws NameNotFoundException {
+        return getPackageInfoAsUser(packageName, flags, mContext.getUserId());
+    }
+
+    @Override
+    public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
         try {
-            PackageInfo pi = mPM.getPackageInfo(packageName, flags, mContext.getUserId());
+            PackageInfo pi = mPM.getPackageInfo(packageName, flags, userId);
             if (pi != null) {
                 return pi;
             }
@@ -1338,7 +1344,7 @@
         final VerificationParams verificationParams = new VerificationParams(null, null,
                 null, VerificationParams.NO_UID, null);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, null);
+                installerPackageName, verificationParams, null, mContext.getUserId());
     }
 
     @Override
@@ -1348,7 +1354,7 @@
         final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
                 null, VerificationParams.NO_UID, manifestDigest);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, encryptionParams);
+                installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
     }
 
     @Override
@@ -1356,15 +1362,23 @@
             IPackageInstallObserver observer, int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
-                installerPackageName, verificationParams, encryptionParams);
+                installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
     }
 
     @Override
     public void installPackage(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName) {
+        installPackageAsUser(packageURI, observer, flags, installerPackageName,
+                mContext.getUserId());
+    }
+
+    @Override
+    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
+               String installerPackageName, int userId) {
         final VerificationParams verificationParams = new VerificationParams(null, null,
                 null, VerificationParams.NO_UID, null);
-        installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null);
+        installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
+                userId);
     }
 
     @Override
@@ -1375,7 +1389,7 @@
         final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
                 null, VerificationParams.NO_UID, manifestDigest);
         installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
-                encryptionParams);
+                encryptionParams, mContext.getUserId());
     }
 
     @Override
@@ -1383,12 +1397,13 @@
             PackageInstallObserver observer, int flags, String installerPackageName,
             VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
         installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
-                encryptionParams);
+                encryptionParams, mContext.getUserId());
     }
 
     private void installCommon(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams) {
+            VerificationParams verificationParams, ContainerEncryptionParams encryptionParams,
+            int userId) {
         if (!"file".equals(packageURI.getScheme())) {
             throw new UnsupportedOperationException("Only file:// URIs are supported");
         }
@@ -1398,17 +1413,22 @@
 
         final String originPath = packageURI.getPath();
         try {
-            mPM.installPackage(originPath, observer.getBinder(), flags, installerPackageName,
-                    verificationParams, null);
+            mPM.installPackageAsUser(originPath, observer.getBinder(), flags, installerPackageName,
+                    verificationParams, null, userId);
         } catch (RemoteException ignored) {
         }
     }
 
     @Override
-    public int installExistingPackage(String packageName)
+    public int installExistingPackage(String packageName) throws NameNotFoundException {
+        return installExistingPackageAsUser(packageName, mContext.getUserId());
+    }
+
+    @Override
+    public int installExistingPackageAsUser(String packageName, int userId)
             throws NameNotFoundException {
         try {
-            int res = mPM.installExistingPackageAsUser(packageName, UserHandle.myUserId());
+            int res = mPM.installExistingPackageAsUser(packageName, userId);
             if (res == INSTALL_FAILED_INVALID_URI) {
                 throw new NameNotFoundException("Package " + packageName + " doesn't exist");
             }
@@ -1706,8 +1726,14 @@
 
     @Override
     public void deletePackage(String packageName, IPackageDeleteObserver observer, int flags) {
+        deletePackageAsUser(packageName, observer, flags, mContext.getUserId());
+    }
+
+    @Override
+    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
+            int userId) {
         try {
-            mPM.deletePackageAsUser(packageName, observer, UserHandle.myUserId(), flags);
+            mPM.deletePackageAsUser(packageName, observer, userId, flags);
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -1812,7 +1838,7 @@
     public void replacePreferredActivity(IntentFilter filter,
                                          int match, ComponentName[] set, ComponentName activity) {
         try {
-            mPM.replacePreferredActivity(filter, match, set, activity, UserHandle.myUserId());
+            mPM.replacePreferredActivity(filter, match, set, activity, mContext.getUserId());
         } catch (RemoteException e) {
             // Should never happen!
         }
@@ -2143,7 +2169,7 @@
     }
 
     private UserInfo getUserIfProfile(int userHandle) {
-        List<UserInfo> userProfiles = getUserManager().getProfiles(UserHandle.myUserId());
+        List<UserInfo> userProfiles = getUserManager().getProfiles(mContext.getUserId());
         for (UserInfo user : userProfiles) {
             if (user.id == userHandle) {
                 return user;
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/core/java/android/app/AutomaticZenRule.aidl
similarity index 68%
copy from packages/SystemUI/res/values-sw600dp-port/dimens.xml
copy to core/java/android/app/AutomaticZenRule.aidl
index 7dc91d1..feb21d6 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/core/java/android/app/AutomaticZenRule.aidl
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, The Android Open Source Project
+/**
+ * Copyright (c) 2015, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,9 +12,8 @@
  * 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>
-    <!-- Recent Applications parameters -->
-    <dimen name="status_bar_recents_app_label_width">140dip</dimen>
-</resources>
+ */
+
+package android.app;
+
+parcelable AutomaticZenRule;
\ No newline at end of file
diff --git a/core/java/android/app/AutomaticZenRule.java b/core/java/android/app/AutomaticZenRule.java
new file mode 100644
index 0000000..fea5624
--- /dev/null
+++ b/core/java/android/app/AutomaticZenRule.java
@@ -0,0 +1,190 @@
+/**
+ * Copyright (c) 2015, 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.app;
+
+import android.content.ComponentName;
+import android.net.Uri;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Objects;
+
+/**
+ * Rule instance information for zen mode.
+ */
+public class AutomaticZenRule implements Parcelable {
+
+    private boolean enabled = false;
+    private String name;
+    private int interruptionFilter;
+    private Uri conditionId;
+    private ComponentName owner;
+
+    /**
+     * Creates an automatic zen rule.
+     *
+     * @param name The name of the rule.
+     * @param owner The Condition Provider service that owns this rule.
+     * @param conditionId A representation of the state that should cause the Condition Provider
+     *                    service to apply the interruption filter.
+     * @param interruptionFilter The interruption filter defines which notifications are allowed to
+     *                           interrupt the user (e.g. via sound &amp; vibration) while this rule
+     *                           is active.
+     * @param enabled Whether the rule is enabled.
+     */
+    public AutomaticZenRule(String name, ComponentName owner, Uri conditionId,
+            int interruptionFilter, boolean enabled) {
+        this.name = name;
+        this.owner = owner;
+        this.conditionId = conditionId;
+        this.interruptionFilter = interruptionFilter;
+        this.enabled = enabled;
+    }
+
+    public AutomaticZenRule(Parcel source) {
+        enabled = source.readInt() == 1;
+        if (source.readInt() == 1) {
+            name = source.readString();
+        }
+        interruptionFilter = source.readInt();
+        conditionId = source.readParcelable(null);
+        owner = source.readParcelable(null);
+    }
+
+    /**
+     * Returns the {@link ComponentName} of the condition provider service that owns this rule.
+     */
+    public ComponentName getOwner() {
+        return owner;
+    }
+
+    /**
+     * Returns the representation of the state that causes this rule to become active.
+     */
+    public Uri getConditionId() {
+        return conditionId;
+    }
+
+    /**
+     * Returns the interruption filter that is applied when this rule is active.
+     */
+    public int getInterruptionFilter() {
+        return interruptionFilter;
+    }
+
+    /**
+     * Returns the name of this rule.
+     */
+    public String getName() {
+        return name;
+    }
+
+    /**
+     * Returns whether this rule is enabled.
+     */
+    public boolean isEnabled() {
+        return enabled;
+    }
+
+    /**
+     * Sets the representation of the state that causes this rule to become active.
+     */
+    public void setConditionId(Uri conditionId) {
+        this.conditionId = conditionId;
+    }
+
+    /**
+     * Sets the interruption filter that is applied when this rule is active.
+     * @param interruptionFilter One of the INTERRUPTION_FILTER_ constants in NotificationManager.
+     */
+    public void setInterruptionFilter(int interruptionFilter) {
+        this.interruptionFilter = interruptionFilter;
+    }
+
+    /**
+     * Sets the name of this rule.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    /**
+     * Enables this rule.
+     */
+    public void setEnabled(boolean enabled) {
+        this.enabled = enabled;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeInt(enabled ? 1 : 0);
+        if (name != null) {
+            dest.writeInt(1);
+            dest.writeString(name);
+        } else {
+            dest.writeInt(0);
+        }
+        dest.writeInt(interruptionFilter);
+        dest.writeParcelable(conditionId, 0);
+        dest.writeParcelable(owner, 0);
+    }
+
+    @Override
+    public String toString() {
+        return new StringBuilder(AutomaticZenRule.class.getSimpleName()).append('[')
+                .append("enabled=").append(enabled)
+                .append(",name=").append(name)
+                .append(",interruptionFilter=").append(interruptionFilter)
+                .append(",conditionId=").append(conditionId)
+                .append(",owner=").append(owner)
+                .append(']').toString();
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (!(o instanceof AutomaticZenRule)) return false;
+        if (o == this) return true;
+        final AutomaticZenRule other = (AutomaticZenRule) o;
+        return other.enabled == enabled
+                && Objects.equals(other.name, name)
+                && other.interruptionFilter == interruptionFilter
+                && Objects.equals(other.conditionId, conditionId)
+                && Objects.equals(other.owner, owner);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(enabled, name, interruptionFilter, conditionId, owner);
+    }
+
+    public static final Parcelable.Creator<AutomaticZenRule> CREATOR
+            = new Parcelable.Creator<AutomaticZenRule>() {
+        @Override
+        public AutomaticZenRule createFromParcel(Parcel source) {
+            return new AutomaticZenRule(source);
+        }
+        @Override
+        public AutomaticZenRule[] newArray(int size) {
+            return new AutomaticZenRule[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 2180bcc..478fdd1 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -535,6 +535,8 @@
     public int getActivityStackId(IBinder token) throws RemoteException;
     public void moveActivityToStack(IBinder token, int stackId) throws RemoteException;
 
+    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -891,4 +893,5 @@
     int MOVE_ACTIVITY_TO_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 344;
     int REPORT_SIZE_CONFIGURATIONS = IBinder.FIRST_CALL_TRANSACTION + 345;
     int MOVE_TASK_TO_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 346;
+    int SUPPRESS_RESIZE_CONFIG_CHANGES_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 347;
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index f78fb47..920fbe9 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -30,6 +30,7 @@
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
 import android.service.notification.StatusBarNotification;
+import android.app.AutomaticZenRule;
 import android.service.notification.ZenModeConfig;
 
 /** {@hide} */
@@ -92,6 +93,11 @@
     String[] getPackagesRequestingNotificationPolicyAccess();
     boolean isNotificationPolicyAccessGrantedForPackage(String pkg);
     void setNotificationPolicyAccessGranted(String pkg, boolean granted);
+    AutomaticZenRule getAutomaticZenRule(String name);
+    List<AutomaticZenRule> getAutomaticZenRules();
+    boolean addOrUpdateAutomaticZenRule(in AutomaticZenRule automaticZenRule);
+    boolean renameAutomaticZenRule(String oldName, String newName);
+    boolean removeAutomaticZenRule(String name);
 
     byte[] getBackupPayload(int user);
     void applyRestore(in byte[] payload, int user);
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 605c006..cbf198b 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -420,6 +420,106 @@
     }
 
     /**
+     * Returns AutomaticZenRules owned by the caller.
+     *
+     * <p>
+     * Only available if policy access is granted to this package.
+     * See {@link #isNotificationPolicyAccessGranted}.
+     */
+    public List<AutomaticZenRule> getAutomaticZenRules() {
+        INotificationManager service = getService();
+        try {
+            return service.getAutomaticZenRules();
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    /**
+     * Returns the AutomaticZenRule with the given name, if it exists and the caller has access.
+     *
+     * <p>
+     * Only available if policy access is granted to this package.
+     * See {@link #isNotificationPolicyAccessGranted}.
+     *
+     * <p>
+     * Returns null if there are no zen rules that match the given name, or if the calling package
+     * doesn't own the matching rule. See {@link AutomaticZenRule#getOwner}.
+     */
+    public AutomaticZenRule getAutomaticZenRule(String name) {
+        INotificationManager service = getService();
+        try {
+            return service.getAutomaticZenRule(name);
+        } catch (RemoteException e) {
+        }
+        return null;
+    }
+
+    /**
+     * Creates or updates the given zen rule.
+     *
+     * <p>
+     * Only available if policy access is granted to this package.
+     * See {@link #isNotificationPolicyAccessGranted}.
+     *
+     * <p>
+     * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
+     * @param automaticZenRule the rule to create or update.
+     * @return Whether the rule was successfully created or updated.
+     */
+    public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule) {
+        INotificationManager service = getService();
+        try {
+            return service.addOrUpdateAutomaticZenRule(automaticZenRule);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Renames a zen rule.
+     *
+     * <p>
+     * Only available if policy access is granted to this package.
+     * See {@link #isNotificationPolicyAccessGranted}.
+     *
+     * <p>
+     * Callers can only update rules that they own. See {@link AutomaticZenRule#getOwner}.
+     * @param oldName The name of the rule to update.
+     * @param newName The new name for the rule.
+     * @return Whether the rule was successfully updated.
+     */
+    public boolean renameAutomaticZenRule(String oldName, String newName) {
+        INotificationManager service = getService();
+        try {
+            return service.renameAutomaticZenRule(oldName, newName);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
+     * Deletes the automatic zen rule with the given name.
+     *
+     * <p>
+     * Only available if policy access is granted to this package.
+     * See {@link #isNotificationPolicyAccessGranted}.
+     *
+     * <p>
+     * Callers can only delete rules that they own. See {@link AutomaticZenRule#getOwner}.
+     * @param name the name of the rule to delete.
+     * @return Whether the rule was successfully deleted.
+     */
+    public boolean removeAutomaticZenRule(String name) {
+        INotificationManager service = getService();
+        try {
+            return service.removeAutomaticZenRule(name);
+        } catch (RemoteException e) {
+        }
+        return false;
+    }
+
+    /**
      * Checks the ability to read/modify notification policy for the calling package.
      *
      * <p>
diff --git a/core/java/android/app/StatusBarManager.java b/core/java/android/app/StatusBarManager.java
index 31d1ab7..5e8ad68 100644
--- a/core/java/android/app/StatusBarManager.java
+++ b/core/java/android/app/StatusBarManager.java
@@ -90,6 +90,9 @@
     public static final int WINDOW_STATE_HIDING = 1;
     public static final int WINDOW_STATE_HIDDEN = 2;
 
+    public static final int CAMERA_LAUNCH_SOURCE_WIGGLE = 0;
+    public static final int CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = 1;
+
     private Context mContext;
     private IStatusBarService mService;
     private IBinder mToken = new Binder();
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e6484e9..a118f16 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -2438,6 +2438,17 @@
     }
 
     /**
+     * Determine whether or not creating a guest user has been disabled for the device
+     *
+     * @hide
+     */
+    public boolean getGuestUserDisabled(@Nullable ComponentName admin) {
+        // Currently guest users can always be created if multi-user is enabled
+        // TODO introduce a policy for guest user creation
+        return false;
+    }
+
+    /**
      * Called by a device/profile owner to set whether the screen capture is disabled. Disabling
      * screen capture also prevents the content from being shown on display devices that do not have
      * a secure video output. See {@link android.view.Display#FLAG_SECURE} for more details about
diff --git a/core/java/android/app/backup/BackupAgent.java b/core/java/android/app/backup/BackupAgent.java
index 689283c..aa4a631 100644
--- a/core/java/android/app/backup/BackupAgent.java
+++ b/core/java/android/app/backup/BackupAgent.java
@@ -533,6 +533,14 @@
                 File file = scanQueue.remove(0);
                 String filePath;
                 try {
+                    // Ignore symlinks outright
+                    StructStat stat = Os.lstat(file.getPath());
+                    if (OsConstants.S_ISLNK(stat.st_mode)) {
+                        if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
+                        continue;
+                    }
+
+                    // For all other verification, look at the canonicalized path
                     filePath = file.getCanonicalPath();
 
                     // prune this subtree?
@@ -544,11 +552,7 @@
                     }
 
                     // If it's a directory, enqueue its contents for scanning.
-                    StructStat stat = Os.lstat(filePath);
-                    if (OsConstants.S_ISLNK(stat.st_mode)) {
-                        if (DEBUG) Log.i(TAG, "Symlink (skipping)!: " + file);
-                        continue;
-                    } else if (OsConstants.S_ISDIR(stat.st_mode)) {
+                    if (OsConstants.S_ISDIR(stat.st_mode)) {
                         File[] contents = file.listFiles();
                         if (contents != null) {
                             for (File entry : contents) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index b08db20..670ca80 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3033,6 +3033,39 @@
     public static final String EXTRA_PROCESS_TEXT_READONLY =
             "android.intent.extra.PROCESS_TEXT_READONLY";
 
+    /**
+     * Broadcast action: reports when a new thermal event has been reached. When the device
+     * is reaching its maximum temperatue, the thermal level reported
+     * {@hide}
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_THERMAL_EVENT = "android.intent.action.THERMAL_EVENT";
+
+    /** {@hide} */
+    public static final String EXTRA_THERMAL_STATE = "android.intent.extra.THERMAL_STATE";
+
+    /**
+     * Thermal state when the device is normal. This state is sent in the
+     * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+     * {@hide}
+     */
+    public static final int EXTRA_THERMAL_STATE_NORMAL = 0;
+
+    /**
+     * Thermal state where the device is approaching its maximum threshold. This state is sent in
+     * the {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+     * {@hide}
+     */
+    public static final int EXTRA_THERMAL_STATE_WARNING = 1;
+
+    /**
+     * Thermal state where the device has reached its maximum threshold. This state is sent in the
+     * {@link ACTION_THERMAL_EVENT} broadcast as {@link EXTRA_THERMAL_STATE}.
+     * {@hide}
+     */
+    public static final int EXTRA_THERMAL_STATE_EXCEEDED = 2;
+
+
     // ---------------------------------------------------------------------
     // ---------------------------------------------------------------------
     // Standard intent categories (see addCategory()).
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c8e9402..697b946 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2010,7 +2010,7 @@
      *            {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
      *            {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
      *            modify the data returned.
-     * @return Returns a PackageInfo object containing information about the
+     * @return A PackageInfo object containing information about the
      *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
      *         package is not found in the list of installed applications, the
      *         package information is retrieved from the list of uninstalled
@@ -2032,6 +2032,46 @@
             throws NameNotFoundException;
 
     /**
+     * @hide
+     * Retrieve overall information about an application package that is
+     * installed on the system.
+     * <p>
+     * Throws {@link NameNotFoundException} if a package with the given name can
+     * not be found on the system.
+     *
+     * @param packageName The full name (i.e. com.google.apps.contacts) of the
+     *            desired package.
+     * @param flags Additional option flags. Use any combination of
+     *            {@link #GET_ACTIVITIES}, {@link #GET_GIDS},
+     *            {@link #GET_CONFIGURATIONS}, {@link #GET_INSTRUMENTATION},
+     *            {@link #GET_PERMISSIONS}, {@link #GET_PROVIDERS},
+     *            {@link #GET_RECEIVERS}, {@link #GET_SERVICES},
+     *            {@link #GET_SIGNATURES}, {@link #GET_UNINSTALLED_PACKAGES} to
+     *            modify the data returned.
+     * @param userId The user id.
+     * @return A PackageInfo object containing information about the
+     *         package. If flag GET_UNINSTALLED_PACKAGES is set and if the
+     *         package is not found in the list of installed applications, the
+     *         package information is retrieved from the list of uninstalled
+     *         applications (which includes installed applications as well as
+     *         applications with data directory i.e. applications which had been
+     *         deleted with {@code DONT_DELETE_DATA} flag set).
+     * @see #GET_ACTIVITIES
+     * @see #GET_GIDS
+     * @see #GET_CONFIGURATIONS
+     * @see #GET_INSTRUMENTATION
+     * @see #GET_PERMISSIONS
+     * @see #GET_PROVIDERS
+     * @see #GET_RECEIVERS
+     * @see #GET_SERVICES
+     * @see #GET_SIGNATURES
+     * @see #GET_UNINSTALLED_PACKAGES
+     */
+    @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
+    public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException;
+
+    /**
      * Map from the current package names in use on the device to whatever
      * the current canonical name of that package is.
      * @param names Array of current names to be mapped.
@@ -3689,6 +3729,31 @@
             Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName);
 
+
+    /**
+     * @hide
+     * Install a package. Since this may take a little while, the result will be
+     * posted back to the given observer. An installation will fail if the package named
+     * in the package file's manifest is already installed, or if there's no space
+     * available on the device.
+     * @param packageURI The location of the package file to install. This can be a 'file:' or a
+     * 'content:' URI.
+     * @param observer An observer callback to get notified when the package installation is
+     * complete. {@link PackageInstallObserver#packageInstalled(String, Bundle, int)} will be
+     * called when that happens. This parameter must not be null.
+     * @param flags - possible values: {@link #INSTALL_FORWARD_LOCK},
+     * {@link #INSTALL_REPLACE_EXISTING}, {@link #INSTALL_ALLOW_TEST}.
+     * @param installerPackageName Optional package name of the application that is performing the
+     * installation. This identifies which market the package came from.
+     * @param userId The user id.
+     */
+     @RequiresPermission(anyOf = {
+            Manifest.permission.INSTALL_PACKAGES,
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    public abstract void installPackageAsUser(
+            Uri packageURI, PackageInstallObserver observer, int flags,
+            String installerPackageName, int userId);
+
     /**
      * Similar to
      * {@link #installPackage(Uri, IPackageInstallObserver, int, String)} but
@@ -3752,7 +3817,17 @@
      * @hide
      */
     // @SystemApi
-    public abstract int installExistingPackage(String packageName)
+    public abstract int installExistingPackage(String packageName) throws NameNotFoundException;
+
+    /**
+     * If there is already an application with the given package name installed
+     * on the system for other users, also install it for the specified user.
+     * @hide
+     */
+     @RequiresPermission(anyOf = {
+            Manifest.permission.INSTALL_PACKAGES,
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    public abstract int installExistingPackageAsUser(String packageName, int userId)
             throws NameNotFoundException;
 
     /**
@@ -3958,7 +4033,7 @@
      * @param observer An observer callback to get notified when the package deletion is
      * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
      * called when that happens.  observer may be null to indicate that no callback is desired.
-     * @param flags - possible values: {@link #DELETE_KEEP_DATA},
+     * @param flags Possible values: {@link #DELETE_KEEP_DATA},
      * {@link #DELETE_ALL_USERS}.
      *
      * @hide
@@ -3968,6 +4043,27 @@
             String packageName, IPackageDeleteObserver observer, int flags);
 
     /**
+     * Attempts to delete a package.  Since this may take a little while, the result will
+     * be posted back to the given observer. A deletion will fail if the named package cannot be
+     * found, or if the named package is a "system package".
+     * (TODO: include pointer to documentation on "system packages")
+     *
+     * @param packageName The name of the package to delete
+     * @param observer An observer callback to get notified when the package deletion is
+     * complete. {@link android.content.pm.IPackageDeleteObserver#packageDeleted(boolean)} will be
+     * called when that happens.  observer may be null to indicate that no callback is desired.
+     * @param flags Possible values: {@link #DELETE_KEEP_DATA}, {@link #DELETE_ALL_USERS}.
+     * @param userId The user Id
+     *
+     * @hide
+     */
+     @RequiresPermission(anyOf = {
+            Manifest.permission.DELETE_PACKAGES,
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL})
+    public abstract void deletePackageAsUser(
+            String packageName, IPackageDeleteObserver observer, int flags, int userId);
+
+    /**
      * Retrieve the package name of the application that installed a package. This identifies
      * which market the package came from.
      *
diff --git a/core/java/android/content/pm/UserInfo.java b/core/java/android/content/pm/UserInfo.java
index 7392563..d7c2215 100644
--- a/core/java/android/content/pm/UserInfo.java
+++ b/core/java/android/content/pm/UserInfo.java
@@ -136,7 +136,16 @@
      * the method always returns false.
      */
     public boolean isSystemOnly() {
-        return id == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser();
+        return isSystemOnly(id);
+    }
+
+    /**
+     * Returns true if the given user is a split system user.
+     * <p>If {@link UserManager#isSplitSystemUser split system user mode} is not enabled,
+     * the method always returns false.
+     */
+    public static boolean isSystemOnly(int userId) {
+        return userId == UserHandle.USER_SYSTEM && UserManager.isSplitSystemUser();
     }
 
     /**
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index e29bd2c..0606e35 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -16,24 +16,14 @@
 
 package android.content.res;
 
-import android.annotation.AttrRes;
-import android.annotation.ColorInt;
-import android.annotation.StyleRes;
-import android.annotation.StyleableRes;
-import android.graphics.drawable.DrawableInflater;
-import android.icu.text.PluralRules;
-import com.android.internal.util.GrowingArrayUtils;
-import com.android.internal.util.XmlUtils;
-
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
-
 import android.animation.Animator;
 import android.animation.StateListAnimator;
 import android.annotation.AnimRes;
 import android.annotation.AnyRes;
 import android.annotation.ArrayRes;
+import android.annotation.AttrRes;
 import android.annotation.BoolRes;
+import android.annotation.ColorInt;
 import android.annotation.ColorRes;
 import android.annotation.DimenRes;
 import android.annotation.DrawableRes;
@@ -45,18 +35,23 @@
 import android.annotation.PluralsRes;
 import android.annotation.RawRes;
 import android.annotation.StringRes;
+import android.annotation.StyleRes;
+import android.annotation.StyleableRes;
 import android.annotation.XmlRes;
 import android.content.pm.ActivityInfo;
 import android.graphics.Movie;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Drawable.ConstantState;
+import android.graphics.drawable.DrawableInflater;
+import android.icu.text.PluralRules;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
+import android.util.LocaleList;
 import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.Pools.SynchronizedPool;
@@ -65,6 +60,12 @@
 import android.view.ViewDebug;
 import android.view.ViewHierarchyEncoder;
 
+import com.android.internal.util.GrowingArrayUtils;
+import com.android.internal.util.XmlUtils;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.lang.ref.WeakReference;
@@ -372,7 +373,7 @@
     private PluralRules getPluralRule() {
         synchronized (sSync) {
             if (mPluralRule == null) {
-                mPluralRule = PluralRules.forLocale(mConfiguration.locale);
+                mPluralRule = PluralRules.forLocale(mConfiguration.getLocales().getPrimary());
             }
             return mPluralRule;
         }
@@ -435,7 +436,7 @@
     @NonNull
     public String getString(@StringRes int id, Object... formatArgs) throws NotFoundException {
         final String raw = getString(id);
-        return String.format(mConfiguration.locale, raw, formatArgs);
+        return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
     }
 
     /**
@@ -466,7 +467,7 @@
     public String getQuantityString(@PluralsRes int id, int quantity, Object... formatArgs)
             throws NotFoundException {
         String raw = getQuantityText(id, quantity).toString();
-        return String.format(mConfiguration.locale, raw, formatArgs);
+        return String.format(mConfiguration.getLocales().getPrimary(), raw, formatArgs);
     }
 
     /**
@@ -1971,9 +1972,10 @@
             mCompatibilityInfo.applyToDisplayMetrics(mMetrics);
 
             final int configChanges = calcConfigChanges(config);
-            if (mConfiguration.locale == null) {
-                mConfiguration.locale = Locale.getDefault();
-                mConfiguration.setLayoutDirection(mConfiguration.locale);
+            LocaleList locales = mConfiguration.getLocales();
+            if (locales.isEmpty()) {
+                locales = LocaleList.getDefault();
+                mConfiguration.setLocales(locales);
             }
             if (mConfiguration.densityDpi != Configuration.DENSITY_DPI_UNDEFINED) {
                 mMetrics.densityDpi = mConfiguration.densityDpi;
@@ -1981,11 +1983,6 @@
             }
             mMetrics.scaledDensity = mMetrics.density * mConfiguration.fontScale;
 
-            String locale = null;
-            if (mConfiguration.locale != null) {
-                locale = adjustLanguageTag(mConfiguration.locale.toLanguageTag());
-            }
-
             final int width, height;
             if (mMetrics.widthPixels >= mMetrics.heightPixels) {
                 width = mMetrics.widthPixels;
@@ -2005,8 +2002,10 @@
                 keyboardHidden = mConfiguration.keyboardHidden;
             }
 
+            // TODO: Pass the whole locale list to setConfiguration()
             mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
-                    locale, mConfiguration.orientation,
+                    adjustLanguageTag(locales.getPrimary().toLanguageTag()),
+                    mConfiguration.orientation,
                     mConfiguration.touchscreen,
                     mConfiguration.densityDpi, mConfiguration.keyboard,
                     keyboardHidden, mConfiguration.navigation, width, height,
@@ -2030,7 +2029,7 @@
         }
         synchronized (sSync) {
             if (mPluralRule != null) {
-                mPluralRule = PluralRules.forLocale(config.locale);
+                mPluralRule = PluralRules.forLocale(config.getLocales().getPrimary());
             }
         }
     }
@@ -2049,9 +2048,8 @@
 
             mCompatibilityInfo.applyToConfiguration(density, mTmpConfig);
 
-            if (mTmpConfig.locale == null) {
-                mTmpConfig.locale = Locale.getDefault();
-                mTmpConfig.setLayoutDirection(mTmpConfig.locale);
+            if (mTmpConfig.getLocales().isEmpty()) {
+                mTmpConfig.setLocales(LocaleList.getDefault());
             }
             configChanges = mConfiguration.updateFrom(mTmpConfig);
             configChanges = ActivityInfo.activityInfoConfigToNative(configChanges);
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index 9a2a241..444548f 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -208,6 +208,12 @@
      * {@link android.content.Intent#getParcelableExtra(String)}.
      */
     public static final String EXTRA_CAPTIVE_PORTAL = "android.net.extra.CAPTIVE_PORTAL";
+
+    /**
+     * Key for passing a URL to the captive portal login activity.
+     */
+    public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
+
     /**
      * Broadcast action to indicate the change of data activity status
      * (idle or active) on a network in a recent period.
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index cfa6164..c4501ba 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -157,7 +157,7 @@
      * incoming transaction, then its own UserHandle is returned.
      */
     public static final UserHandle getCallingUserHandle() {
-        return new UserHandle(UserHandle.getUserId(getCallingUid()));
+        return UserHandle.of(UserHandle.getUserId(getCallingUid()));
     }
 
     /**
diff --git a/core/java/android/os/IPowerManager.aidl b/core/java/android/os/IPowerManager.aidl
index c4f62ba..9fdbec3 100644
--- a/core/java/android/os/IPowerManager.aidl
+++ b/core/java/android/os/IPowerManager.aidl
@@ -23,8 +23,11 @@
 
 interface IPowerManager
 {
-    // WARNING: The first five methods must remain the first five methods because their
-    // transaction numbers must not change unless IPowerManager.cpp is also updated.
+    // WARNING: When methods are inserted or deleted, the transaction IDs in
+    // frameworks/native/include/powermanager/IPowerManager.h must be updated to match the order in this file.
+    //
+    // When a method's argument list is changed, BnPowerManager's corresponding serialization code (if any) in
+    // frameworks/native/services/powermanager/IPowerManager.cpp must be updated.
     void acquireWakeLock(IBinder lock, int flags, String tag, String packageName, in WorkSource ws,
             String historyTag);
     void acquireWakeLockWithUid(IBinder lock, int flags, String tag, String packageName,
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index aeb5d45..4c19ddd 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -35,6 +35,7 @@
 
     UserInfo createUser(in String name, int flags);
     UserInfo createProfileForUser(in String name, int flags, int userHandle);
+    UserInfo createRestrictedProfile(String name, int parentUserId);
     void setUserEnabled(int userHandle);
     boolean removeUser(int userHandle);
     void setUserName(int userHandle, String name);
@@ -48,6 +49,7 @@
     UserInfo getUserInfo(int userHandle);
     long getUserCreationTime(int userHandle);
     boolean isRestricted();
+    boolean canHaveRestrictedProfile(int userId);
     int getUserSerialNumber(int userHandle);
     int getUserHandle(int userSerialNumber);
     Bundle getUserRestrictions(int userHandle);
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 7234e98..4ac361d0 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -797,8 +797,8 @@
      * {@link #myUid()} in that a particular user will have multiple
      * distinct apps running under it each with their own uid.
      */
-    public static final UserHandle myUserHandle() {
-        return new UserHandle(UserHandle.getUserId(myUid()));
+    public static UserHandle myUserHandle() {
+        return UserHandle.of(UserHandle.getUserId(myUid()));
     }
 
     /**
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index 87ce12c..8b2c74f 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -1923,7 +1923,7 @@
             if (LOG_V) Log.d(TAG, "strict mode violation stacks read from binder call.  i=" + i);
             ViolationInfo info = new ViolationInfo(p, !currentlyGathering);
             if (info.crashInfo.stackTrace != null && info.crashInfo.stackTrace.length() > 30000) {
-                String front = info.crashInfo.stackTrace.substring(256);
+                String front = info.crashInfo.stackTrace.substring(0, 256);
                 // 30000 characters is way too large for this to be any sane kind of
                 // strict mode collection of stacks.  We've had a problem where we leave
                 // strict mode violations associated with the thread, and it keeps tacking
diff --git a/core/java/android/os/UserHandle.java b/core/java/android/os/UserHandle.java
index 213e083..796addc 100644
--- a/core/java/android/os/UserHandle.java
+++ b/core/java/android/os/UserHandle.java
@@ -17,7 +17,6 @@
 package android.os;
 
 import android.annotation.SystemApi;
-import android.util.SparseArray;
 
 import java.io.PrintWriter;
 
@@ -83,8 +82,6 @@
 
     final int mHandle;
 
-    private static final SparseArray<UserHandle> userHandles = new SparseArray<UserHandle>();
-
     /**
      * Checks to see if the user id is the same for the two uids, i.e., they belong to the same
      * user.
@@ -144,15 +141,8 @@
     }
 
     /** @hide */
-    public static UserHandle getCallingUserHandle() {
-        int userId = getUserId(Binder.getCallingUid());
-        UserHandle userHandle = userHandles.get(userId);
-        // Intentionally not synchronized to save time
-        if (userHandle == null) {
-            userHandle = new UserHandle(userId);
-            userHandles.put(userId, userHandle);
-        }
-        return userHandle;
+    public static UserHandle of(int userId) {
+        return userId == USER_SYSTEM ? SYSTEM : new UserHandle(userId);
     }
 
     /**
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 64e2505..d178d20 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -15,10 +15,12 @@
  */
 package android.os;
 
+import android.accounts.AccountManager;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
+import android.app.admin.DevicePolicyManager;
 import android.content.Context;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
@@ -631,6 +633,19 @@
     }
 
     /**
+     * Checks if specified user can have restricted profile.
+     * @hide
+     */
+    public boolean canHaveRestrictedProfile(int userId) {
+        try {
+            return mService.canHaveRestrictedProfile(userId);
+        } catch (RemoteException re) {
+            Log.w(TAG, "Could not check if user can have restricted profile", re);
+            return false;
+        }
+    }
+
+    /**
      * Checks if the calling app is running as a guest user.
      * @return whether the caller is a guest user.
      * @hide
@@ -927,7 +942,8 @@
     }
 
     /**
-     * Creates a restricted profile with the specified name.
+     * Creates a restricted profile with the specified name. This method also sets necessary
+     * restrictions and adds shared accounts.
      *
      * @param name profile's name
      * @return UserInfo object for the created user, or null if the user could not be created.
@@ -935,13 +951,14 @@
      */
     public UserInfo createRestrictedProfile(String name) {
         try {
-            if (isSplitSystemUser()) {
-                return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
-                        UserHandle.getCallingUserId());
-            } else {
-                return mService.createProfileForUser(name, UserInfo.FLAG_RESTRICTED,
-                        UserHandle.USER_SYSTEM);
+            UserHandle parentUserHandle = Process.myUserHandle();
+            UserInfo user = mService.createRestrictedProfile(name,
+                    parentUserHandle.getIdentifier());
+            if (user != null) {
+                AccountManager.get(mContext).addSharedAccountsFromParentUser(parentUserHandle,
+                        UserHandle.of(user.id));
             }
+            return user;
         } catch (RemoteException e) {
             Log.w(TAG, "Could not create a restricted profile", e);
         }
@@ -1321,12 +1338,15 @@
     }
 
     /**
-     * Returns true if the user switcher should be shown, this will be if there
-     * are multiple users that aren't managed profiles.
+     * Returns true if the user switcher should be shown, this will be if device supports multi-user
+     * and there are at least 2 users available that are not managed profiles.
      * @hide
      * @return true if user switcher should be shown.
      */
     public boolean isUserSwitcherEnabled() {
+        if (!supportsMultipleUsers()) {
+            return false;
+        }
         List<UserInfo> users = getUsers(true);
         if (users == null) {
            return false;
@@ -1337,8 +1357,8 @@
                 ++switchableUserCount;
             }
         }
-        final boolean guestEnabled = Settings.Global.getInt(mContext.getContentResolver(),
-                Settings.Global.GUEST_USER_ENABLED, 0) == 1;
+        final boolean guestEnabled = !mContext.getSystemService(DevicePolicyManager.class)
+                .getGuestUserDisabled(null);
         return switchableUserCount > 1 || guestEnabled;
     }
 
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 6888594..c368e5a 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -438,6 +438,8 @@
         final Intent intent = new Intent(DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT);
         intent.addCategory(Intent.CATEGORY_DEFAULT);
         intent.setData(uri);
+        intent.putExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, true);
+        intent.putExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, true);
         return intent;
     }
 
diff --git a/core/java/android/preference/SeekBarPreference.java b/core/java/android/preference/SeekBarPreference.java
index 67f6409..5414f00 100644
--- a/core/java/android/preference/SeekBarPreference.java
+++ b/core/java/android/preference/SeekBarPreference.java
@@ -96,18 +96,15 @@
 
     @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
-        if (event.getAction() != KeyEvent.ACTION_UP) {
-            if (keyCode == KeyEvent.KEYCODE_PLUS
-                    || keyCode == KeyEvent.KEYCODE_EQUALS) {
-                setProgress(getProgress() + 1);
-                return true;
-            }
-            if (keyCode == KeyEvent.KEYCODE_MINUS) {
-                setProgress(getProgress() - 1);
-                return true;
-            }
+        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+            return false;
         }
-        return false;
+
+        SeekBar seekBar = (SeekBar) v.findViewById(com.android.internal.R.id.seekbar);
+        if (seekBar == null) {
+            return false;
+        }
+        return seekBar.onKeyDown(keyCode, event);
     }
 
     public void setMax(int max) {
diff --git a/core/java/android/provider/DocumentsContract.java b/core/java/android/provider/DocumentsContract.java
index 59609f9..1b104e3 100644
--- a/core/java/android/provider/DocumentsContract.java
+++ b/core/java/android/provider/DocumentsContract.java
@@ -93,6 +93,9 @@
     public static final String EXTRA_SHOW_ADVANCED = "android.content.extra.SHOW_ADVANCED";
 
     /** {@hide} */
+    public static final String EXTRA_SHOW_FILESIZE = "android.content.extra.SHOW_FILESIZE";
+
+    /** {@hide} */
     public static final String EXTRA_TARGET_URI = "android.content.extra.TARGET_URI";
 
     /**
@@ -133,6 +136,9 @@
      */
     private static final int THUMBNAIL_BUFFER_SIZE = (int) (128 * KB_IN_BYTES);
 
+    /** {@hide} */
+    public static final String PACKAGE_DOCUMENTS_UI = "com.android.documentsui";
+
     /**
      * Constants related to a document, including {@link Cursor} column names
      * and flags.
@@ -266,7 +272,7 @@
          * writability of a document may change over time, for example due to
          * remote access changes. This flag indicates that a document client can
          * expect {@link ContentResolver#openOutputStream(Uri)} to succeed.
-         * 
+         *
          * @see #COLUMN_FLAGS
          */
         public static final int FLAG_SUPPORTS_WRITE = 1 << 1;
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 225f0cf..d601831 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7689,14 +7689,6 @@
         public static final String DEVICE_NAME = "device_name";
 
         /**
-         * Whether it should be possible to create a guest user on the device.
-         * <p>
-         * Type: int (0 for disabled, 1 for enabled)
-         * @hide
-         */
-        public static final String GUEST_USER_ENABLED = "guest_user_enabled";
-
-        /**
          * Whether the NetworkScoringService has been first initialized.
          * <p>
          * Type: int (0 for false, 1 for true)
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 6310570..4de903e 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -755,6 +755,10 @@
         return rt;
     }
 
+    public static ComponentName getScheduleConditionProvider() {
+        return new ComponentName(SYSTEM_AUTHORITY, "ScheduleConditionProvider");
+    }
+
     public static class ScheduleInfo {
         public int[] days;
         public int startHour;
@@ -827,6 +831,10 @@
         return rt;
     }
 
+    public static ComponentName getEventConditionProvider() {
+        return new ComponentName(SYSTEM_AUTHORITY, "EventConditionProvider");
+    }
+
     public static class EventInfo {
         public static final int REPLY_ANY_EXCEPT_NO = 0;
         public static final int REPLY_YES_OR_MAYBE = 1;
diff --git a/core/java/android/view/BatchedInputEventReceiver.java b/core/java/android/view/BatchedInputEventReceiver.java
new file mode 100644
index 0000000..b1d28e0
--- /dev/null
+++ b/core/java/android/view/BatchedInputEventReceiver.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 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.Looper;
+
+/**
+ * Similar to {@link InputEventReceiver}, but batches events to vsync boundaries when possible.
+ * @hide
+ */
+public class BatchedInputEventReceiver extends InputEventReceiver {
+    Choreographer mChoreographer;
+    private boolean mBatchedInputScheduled;
+
+    public BatchedInputEventReceiver(
+            InputChannel inputChannel, Looper looper, Choreographer choreographer) {
+        super(inputChannel, looper);
+        mChoreographer = choreographer;
+    }
+
+    @Override
+    public void onBatchedInputEventPending() {
+        scheduleBatchedInput();
+    }
+
+    @Override
+    public void dispose() {
+        unscheduleBatchedInput();
+        super.dispose();
+    }
+
+    void doConsumeBatchedInput(long frameTimeNanos) {
+        if (mBatchedInputScheduled) {
+            mBatchedInputScheduled = false;
+            if (consumeBatchedInputEvents(frameTimeNanos) && frameTimeNanos != -1) {
+                // If we consumed a batch here, we want to go ahead and schedule the
+                // consumption of batched input events on the next frame. Otherwise, we would
+                // wait until we have more input events pending and might get starved by other
+                // things occurring in the process. If the frame time is -1, however, then
+                // we're in a non-batching mode, so there's no need to schedule this.
+                scheduleBatchedInput();
+            }
+        }
+    }
+
+    private void scheduleBatchedInput() {
+        if (!mBatchedInputScheduled) {
+            mBatchedInputScheduled = true;
+            mChoreographer.postCallback(Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
+        }
+    }
+
+    private void unscheduleBatchedInput() {
+        if (mBatchedInputScheduled) {
+            mBatchedInputScheduled = false;
+            mChoreographer.removeCallbacks(
+                    Choreographer.CALLBACK_INPUT, mBatchedInputRunnable, null);
+        }
+    }
+
+    private final class BatchedInputRunnable implements Runnable {
+        @Override
+        public void run() {
+            doConsumeBatchedInput(mChoreographer.getFrameTimeNanos());
+        }
+    }
+    private final BatchedInputRunnable mBatchedInputRunnable = new BatchedInputRunnable();
+}
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 32ef995..7adfa8d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -144,7 +144,6 @@
     void setAppStartingWindow(IBinder token, String pkg, int theme,
             in CompatibilityInfo compatInfo, CharSequence nonLocalizedLabel, int labelRes,
             int icon, int logo, int windowFlags, IBinder transferFrom, boolean createIfNeeded);
-    void setAppWillBeHidden(IBinder token);
     void setAppVisibility(IBinder token, boolean visible);
     void startAppFreezingScreen(IBinder token, int configChanges);
     void stopAppFreezingScreen(IBinder token, boolean force);
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 37312d0..e200bef 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -72,6 +72,9 @@
     private static final String TAG = LayoutInflater.class.getSimpleName();
     private static final boolean DEBUG = false;
 
+    /** Empty stack trace used to avoid log spam in re-throw exceptions. */
+    private static final StackTraceElement[] EMPTY_STACK_TRACE = new StackTraceElement[0];
+
     /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
@@ -532,15 +535,14 @@
                 }
 
             } catch (XmlPullParserException e) {
-                InflateException ex = new InflateException(e.getMessage());
-                ex.initCause(e);
-                throw ex;
+                final InflateException ie = new InflateException(e.getMessage(), e);
+                ie.setStackTrace(EMPTY_STACK_TRACE);
+                throw ie;
             } catch (Exception e) {
-                InflateException ex = new InflateException(
-                        parser.getPositionDescription()
-                                + ": " + e.getMessage());
-                ex.initCause(e);
-                throw ex;
+                final InflateException ie = new InflateException(parser.getPositionDescription()
+                        + ": " + e.getMessage(), e);
+                ie.setStackTrace(EMPTY_STACK_TRACE);
+                throw ie;
             } finally {
                 // Don't retain static reference on context.
                 mConstructorArgs[0] = lastContext;
@@ -625,27 +627,25 @@
             return view;
 
         } catch (NoSuchMethodException e) {
-            InflateException ie = new InflateException(attrs.getPositionDescription()
-                    + ": Error inflating class "
-                    + (prefix != null ? (prefix + name) : name));
-            ie.initCause(e);
+            final InflateException ie = new InflateException(attrs.getPositionDescription()
+                    + ": Error inflating class " + (prefix != null ? (prefix + name) : name), e);
+            ie.setStackTrace(EMPTY_STACK_TRACE);
             throw ie;
 
         } catch (ClassCastException e) {
             // If loaded class is not a View subclass
-            InflateException ie = new InflateException(attrs.getPositionDescription()
-                    + ": Class is not a View "
-                    + (prefix != null ? (prefix + name) : name));
-            ie.initCause(e);
+            final InflateException ie = new InflateException(attrs.getPositionDescription()
+                    + ": Class is not a View " + (prefix != null ? (prefix + name) : name), e);
+            ie.setStackTrace(EMPTY_STACK_TRACE);
             throw ie;
         } catch (ClassNotFoundException e) {
             // If loadClass fails, we should propagate the exception.
             throw e;
         } catch (Exception e) {
-            InflateException ie = new InflateException(attrs.getPositionDescription()
-                    + ": Error inflating class "
-                    + (clazz == null ? "<unknown>" : clazz.getName()));
-            ie.initCause(e);
+            final InflateException ie = new InflateException(
+                    attrs.getPositionDescription() + ": Error inflating class "
+                            + (clazz == null ? "<unknown>" : clazz.getName()), e);
+            ie.setStackTrace(EMPTY_STACK_TRACE);
             throw ie;
         } finally {
             Trace.traceEnd(Trace.TRACE_TAG_VIEW);
@@ -657,8 +657,7 @@
      */
     private void failNotAllowed(String name, String prefix, AttributeSet attrs) {
         throw new InflateException(attrs.getPositionDescription()
-                + ": Class not allowed to be inflated "
-                + (prefix != null ? (prefix + name) : name));
+                + ": Class not allowed to be inflated "+ (prefix != null ? (prefix + name) : name));
     }
 
     /**
@@ -774,14 +773,14 @@
 
         } catch (ClassNotFoundException e) {
             final InflateException ie = new InflateException(attrs.getPositionDescription()
-                    + ": Error inflating class " + name);
-            ie.initCause(e);
+                    + ": Error inflating class " + name, e);
+            ie.setStackTrace(EMPTY_STACK_TRACE);
             throw ie;
 
         } catch (Exception e) {
             final InflateException ie = new InflateException(attrs.getPositionDescription()
-                    + ": Error inflating class " + name);
-            ie.initCause(e);
+                    + ": Error inflating class " + name, e);
+            ie.setStackTrace(EMPTY_STACK_TRACE);
             throw ie;
         }
     }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 2a1d757..2c7a4364 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5388,7 +5388,7 @@
     protected boolean performButtonActionOnTouchDown(MotionEvent event) {
         if (event.getToolType(0) == MotionEvent.TOOL_TYPE_MOUSE &&
             (event.getButtonState() & MotionEvent.BUTTON_SECONDARY) != 0) {
-            showContextMenu(event.getX(), event.getY(), event.getMetaState());
+            showContextMenu(event.getX(), event.getY());
             mPrivateFlags |= PFLAG_CANCEL_NEXT_UP_EVENT;
             return true;
         }
@@ -5409,13 +5409,10 @@
      *
      * @param x The referenced x coordinate.
      * @param y The referenced y coordinate.
-     * @param metaState The keyboard modifiers that were pressed.
      * @return Whether a context menu was displayed.
-     *
-     * @hide
      */
-    public boolean showContextMenu(float x, float y, int metaState) {
-        return showContextMenu();
+    public boolean showContextMenu(float x, float y) {
+        return getParent().showContextMenuForChild(this, x, y);
     }
 
     /**
@@ -6652,12 +6649,24 @@
     }
 
     /**
-     * Sets a delegate for implementing accessibility support via composition as
-     * opposed to inheritance. The delegate's primary use is for implementing
-     * backwards compatible widgets. For more details see {@link AccessibilityDelegate}.
+     * Sets a delegate for implementing accessibility support via composition
+     * (as opposed to inheritance). For more details, see
+     * {@link AccessibilityDelegate}.
+     * <p>
+     * <strong>Note:</strong> On platform versions prior to
+     * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
+     * views in the {@code android.widget.*} package are called <i>before</i>
+     * host methods. This prevents certain properties such as class name from
+     * being modified by overriding
+     * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)},
+     * as any changes will be overwritten by the host class.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
+     * methods are called <i>after</i> host methods, which all properties to be
+     * modified without being overwritten by the host class.
      *
-     * @param delegate The delegate instance.
-     *
+     * @param delegate the object to which accessibility method calls should be
+     *                 delegated
      * @see AccessibilityDelegate
      */
     public void setAccessibilityDelegate(@Nullable AccessibilityDelegate delegate) {
@@ -22280,6 +22289,18 @@
      * corresponding delegate method without altering the behavior of the rest
      * accessibility related methods of the host view.
      * </p>
+     * <p>
+     * <strong>Note:</strong> On platform versions prior to
+     * {@link android.os.Build.VERSION_CODES#M API 23}, delegate methods on
+     * views in the {@code android.widget.*} package are called <i>before</i>
+     * host methods. This prevents certain properties such as class name from
+     * being modified by overriding
+     * {@link AccessibilityDelegate#onInitializeAccessibilityNodeInfo(View, AccessibilityNodeInfo)},
+     * as any changes will be overwritten by the host class.
+     * <p>
+     * Starting in {@link android.os.Build.VERSION_CODES#M API 23}, delegate
+     * methods are called <i>after</i> host methods, which all properties to be
+     * modified without being overwritten by the host class.
      */
     public static class AccessibilityDelegate {
 
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index bdcd998..475ce2f 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -767,6 +767,11 @@
         return mParent != null && mParent.showContextMenuForChild(originalView);
     }
 
+    @Override
+    public boolean showContextMenuForChild(View originalView, float x, float y) {
+        return mParent != null && mParent.showContextMenuForChild(originalView, x, y);
+    }
+
     /**
      * {@inheritDoc}
      */
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index 15b86d1..07f1e2c 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -182,6 +182,17 @@
     public boolean showContextMenuForChild(View originalView);
 
     /**
+     * Bring up a context menu for the specified view at the given x/y offset from
+     * the top left corner.
+     *
+     * @param originalView
+     * @param x The x offset at which to open the menu
+     * @param y The y offset at which to open the menu
+     * @return true if a context menu was displayed
+     */
+    public boolean showContextMenuForChild(View originalView, float x, float y);
+
+    /**
      * Have the parent populate the specified context menu if it has anything to
      * add (and then recurse on its parent).
      * 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 8403c46..f6c60ed 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -6240,6 +6240,11 @@
     }
 
     @Override
+    public boolean showContextMenuForChild(View originalView, float x, float y) {
+        return false;
+    }
+
+    @Override
     public ActionMode startActionModeForChild(View originalView, ActionMode.Callback callback) {
         return null;
     }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 0e7089f..5f4e7af 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -2016,4 +2016,8 @@
     public boolean hasNonClientDecorView() {
         return false;
     }
+
+    /** @hide */
+    public void setTheme(int resId) {
+    }
 }
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 45bc1df..92e473d 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -226,6 +226,7 @@
             @ViewDebug.IntToString(from = TYPE_PRIVATE_PRESENTATION, to = "TYPE_PRIVATE_PRESENTATION"),
             @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION, to = "TYPE_VOICE_INTERACTION"),
             @ViewDebug.IntToString(from = TYPE_VOICE_INTERACTION_STARTING, to = "TYPE_VOICE_INTERACTION_STARTING"),
+            @ViewDebug.IntToString(from = TYPE_DOCK_DIVIDER, to = "TYPE_DOCK_DIVIDER"),
         })
         public int type;
 
@@ -565,6 +566,13 @@
         public static final int TYPE_VOICE_INTERACTION_STARTING = FIRST_SYSTEM_WINDOW+33;
 
         /**
+         * Window for displaying a handle used for resizing docked stacks. This window is owned
+         * by the system process.
+         * @hide
+         */
+        public static final int TYPE_DOCK_DIVIDER = FIRST_SYSTEM_WINDOW+34;
+
+        /**
          * End of types of system windows.
          */
         public static final int LAST_SYSTEM_WINDOW      = 2999;
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index 5724f52..b8faf0c 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -3080,6 +3080,15 @@
     }
 
     private class CheckForLongPress extends WindowRunnnable implements Runnable {
+        private static final int INVALID_COORD = -1;
+        private float mX = INVALID_COORD;
+        private float mY = INVALID_COORD;
+
+        private void setCoords(float x, float y) {
+            mX = x;
+            mY = y;
+        }
+
         @Override
         public void run() {
             final int motionPosition = mMotionPosition;
@@ -3090,7 +3099,11 @@
 
                 boolean handled = false;
                 if (sameWindow() && !mDataChanged) {
-                    handled = performLongPress(child, longPressPosition, longPressId);
+                    if (mX != INVALID_COORD && mY != INVALID_COORD) {
+                        handled = performLongPress(child, longPressPosition, longPressId, mX, mY);
+                    } else {
+                        handled = performLongPress(child, longPressPosition, longPressId);
+                    }
                 }
                 if (handled) {
                     mTouchMode = TOUCH_MODE_REST;
@@ -3146,6 +3159,16 @@
 
     boolean performLongPress(final View child,
             final int longPressPosition, final long longPressId) {
+        return performLongPress(
+                child,
+                longPressPosition,
+                longPressId,
+                CheckForLongPress.INVALID_COORD,
+                CheckForLongPress.INVALID_COORD);
+    }
+
+    boolean performLongPress(final View child,
+            final int longPressPosition, final long longPressId, float x, float y) {
         // CHOICE_MODE_MULTIPLE_MODAL takes over long press.
         if (mChoiceMode == CHOICE_MODE_MULTIPLE_MODAL) {
             if (mChoiceActionMode == null &&
@@ -3163,7 +3186,11 @@
         }
         if (!handled) {
             mContextMenuInfo = createContextMenuInfo(child, longPressPosition, longPressId);
-            handled = super.showContextMenuForChild(AbsListView.this);
+            if (x != CheckForLongPress.INVALID_COORD && y != CheckForLongPress.INVALID_COORD) {
+                handled = super.showContextMenuForChild(AbsListView.this, x, y);
+            } else {
+                handled = super.showContextMenuForChild(AbsListView.this);
+            }
         }
         if (handled) {
             performHapticFeedback(HapticFeedbackConstants.LONG_PRESS);
@@ -3178,17 +3205,17 @@
 
     /** @hide */
     @Override
-    public boolean showContextMenu(float x, float y, int metaState) {
+    public boolean showContextMenu(float x, float y) {
         final int position = pointToPosition((int)x, (int)y);
         if (position != INVALID_POSITION) {
             final long id = mAdapter.getItemId(position);
             View child = getChildAt(position - mFirstPosition);
             if (child != null) {
                 mContextMenuInfo = createContextMenuInfo(child, position, id);
-                return super.showContextMenuForChild(AbsListView.this);
+                return super.showContextMenuForChild(AbsListView.this, x, y);
             }
         }
-        return super.showContextMenu(x, y, metaState);
+        return super.showContextMenu(x, y);
     }
 
     @Override
@@ -3341,6 +3368,7 @@
                             if (mPendingCheckForLongPress == null) {
                                 mPendingCheckForLongPress = new CheckForLongPress();
                             }
+                            mPendingCheckForLongPress.setCoords(x, y);
                             mPendingCheckForLongPress.rememberWindowAttachCount();
                             postDelayed(mPendingCheckForLongPress, longPressTimeout);
                         } else {
diff --git a/core/java/android/widget/AbsSeekBar.java b/core/java/android/widget/AbsSeekBar.java
index 68855ff..10aefe4 100644
--- a/core/java/android/widget/AbsSeekBar.java
+++ b/core/java/android/widget/AbsSeekBar.java
@@ -666,7 +666,7 @@
         progress += scale * max;
 
         setHotspot(x, (int) event.getY());
-        setProgress((int) progress, true);
+        setProgressInternal((int) progress, true, false);
     }
 
     /**
@@ -706,9 +706,12 @@
             int increment = mKeyProgressIncrement;
             switch (keyCode) {
                 case KeyEvent.KEYCODE_DPAD_LEFT:
+                case KeyEvent.KEYCODE_MINUS:
                     increment = -increment;
                     // fallthrough
                 case KeyEvent.KEYCODE_DPAD_RIGHT:
+                case KeyEvent.KEYCODE_PLUS:
+                case KeyEvent.KEYCODE_EQUALS:
                     increment = isLayoutRtl() ? -increment : increment;
 
                     if (setProgressInternal(getProgress() + increment, true, true)) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index fddc40f..f53aa38 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2645,6 +2645,8 @@
         private SuggestionAdapter mSuggestionsAdapter;
         private final Comparator<SuggestionSpan> mSuggestionSpanComparator;
         private final HashMap<SuggestionSpan, Integer> mSpansLengths;
+        private final TextAppearanceSpan mHighlightSpan = new TextAppearanceSpan(
+                mTextView.getContext(), android.R.style.TextAppearance_SuggestionHighlight);
 
         private class CustomPopupWindow extends PopupWindow {
             public CustomPopupWindow(Context context, int defStyleAttr) {
@@ -2710,8 +2712,6 @@
             SuggestionSpan suggestionSpan; // the SuggestionSpan that this TextView represents
             int suggestionIndex; // the index of this suggestion inside suggestionSpan
             SpannableStringBuilder text = new SpannableStringBuilder();
-            TextAppearanceSpan highlightSpan = new TextAppearanceSpan(mTextView.getContext(),
-                    android.R.style.TextAppearance_SuggestionHighlight);
         }
 
         private class SuggestionAdapter extends BaseAdapter {
@@ -2948,7 +2948,7 @@
                     suggestionInfo.suggestionIndex = ADD_TO_DICTIONARY;
                     suggestionInfo.text.replace(0, suggestionInfo.text.length(), mTextView.
                             getContext().getString(com.android.internal.R.string.addToDictionary));
-                    suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, 0,
+                    suggestionInfo.text.setSpan(mHighlightSpan, 0, 0,
                             Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
                     mNumberOfSuggestions++;
@@ -2961,8 +2961,7 @@
             suggestionInfo.suggestionIndex = DELETE_TEXT;
             suggestionInfo.text.replace(0, suggestionInfo.text.length(),
                     mTextView.getContext().getString(com.android.internal.R.string.deleteText));
-            suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0, 0,
-                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            suggestionInfo.text.setSpan(mHighlightSpan, 0, 0, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
             mNumberOfSuggestions++;
 
             if (mSuggestionRangeSpan == null) mSuggestionRangeSpan = new SuggestionRangeSpan();
@@ -2993,8 +2992,8 @@
             suggestionInfo.suggestionEnd = suggestionInfo.suggestionStart
                     + suggestionInfo.text.length();
 
-            suggestionInfo.text.setSpan(suggestionInfo.highlightSpan, 0,
-                    suggestionInfo.text.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
+            suggestionInfo.text.setSpan(mHighlightSpan, 0, suggestionInfo.text.length(),
+                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
 
             // Add the text before and after the span.
             final String textAsString = text.toString();
diff --git a/core/java/android/widget/MenuPopupWindow.java b/core/java/android/widget/MenuPopupWindow.java
index ba77b1b..1fb62d0 100644
--- a/core/java/android/widget/MenuPopupWindow.java
+++ b/core/java/android/widget/MenuPopupWindow.java
@@ -124,8 +124,8 @@
                 }
                 return true;
             } else if (selectedItem != null && keyCode == mRetreatKey) {
-                setSelectedPositionInt(-1);
-                setNextSelectedPositionInt(-1);
+                setSelectedPositionInt(INVALID_POSITION);
+                setNextSelectedPositionInt(INVALID_POSITION);
 
                 ((MenuAdapter) getAdapter()).getAdapterMenu().close();
                 return true;
@@ -152,13 +152,19 @@
             boolean superVal = super.onHoverEvent(ev);
 
             if (dispatchHover && mHoverListener != null) {
-                mHoverListener.onItemHovered(
-                        ((MenuAdapter) getAdapter()).getAdapterMenu(), position);
+                ListAdapter adapter = getAdapter();
+                MenuAdapter menuAdapter;
+                if (adapter instanceof HeaderViewListAdapter) {
+                    menuAdapter = (MenuAdapter) ((HeaderViewListAdapter) adapter)
+                            .getWrappedAdapter();
+                } else {
+                    menuAdapter = (MenuAdapter) adapter;
+                }
+
+                mHoverListener.onItemHovered(menuAdapter.getAdapterMenu(), position);
             }
 
             return superVal;
         }
     }
-
-
 }
\ No newline at end of file
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index f9fa027..7b9de79 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -18,6 +18,7 @@
 
 import com.android.internal.R;
 
+import android.annotation.NonNull;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -1449,11 +1450,13 @@
             anchor.getLocationOnScreen(mScreenLocation);
             onTop = (displayFrame.bottom - mScreenLocation[1] - anchorHeight - yoff) <
                     (mScreenLocation[1] - yoff - displayFrame.top);
-            if (onTop) {
-                p.gravity = Gravity.LEFT | Gravity.BOTTOM;
-                p.y = root.getHeight() - mDrawingLocation[1] + yoff;
-            } else {
-                p.y = mDrawingLocation[1] + anchorHeight + yoff;
+            if (!mOverlapAnchor) {
+                if (onTop) {
+                    p.gravity = Gravity.LEFT | Gravity.BOTTOM;
+                    p.y = root.getHeight() - mDrawingLocation[1] + yoff;
+                } else {
+                    p.y = mDrawingLocation[1] + anchorHeight + yoff;
+                }
             }
         }
 
@@ -1469,13 +1472,21 @@
                 p.width = Math.min(p.width, displayFrameWidth);
             }
 
-            if (onTop) {
-                final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
-                if (popupTop < 0) {
-                    p.y += popupTop;
+            if (mOverlapAnchor) {
+                final int displayFrameHeight = displayFrame.bottom - displayFrame.top;
+                final int bottom = p.y + p.height;
+                if (bottom > displayFrame.bottom) {
+                    p.y -= bottom - displayFrameHeight;
                 }
             } else {
-                p.y = Math.max(p.y, displayFrame.top);
+                if (onTop) {
+                    final int popupTop = mScreenLocation[1] + yoff - mPopupHeight;
+                    if (popupTop < 0) {
+                        p.y += popupTop;
+                    }
+                } else {
+                    p.y = Math.max(p.y, displayFrame.top);
+                }
             }
         }
 
@@ -1494,7 +1505,7 @@
      * @return The maximum available height for the popup to be completely
      *         shown.
      */
-    public int getMaxAvailableHeight(View anchor) {
+    public int getMaxAvailableHeight(@NonNull View anchor) {
         return getMaxAvailableHeight(anchor, 0);
     }
 
@@ -1509,7 +1520,7 @@
      * @return The maximum available height for the popup to be completely
      *         shown.
      */
-    public int getMaxAvailableHeight(View anchor, int yOffset) {
+    public int getMaxAvailableHeight(@NonNull View anchor, int yOffset) {
         return getMaxAvailableHeight(anchor, yOffset, false);
     }
 
@@ -1527,22 +1538,29 @@
      *        bottom decorations
      * @return The maximum available height for the popup to be completely
      *         shown.
-     *
-     * @hide Pending API council approval.
      */
-    public int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
+    public int getMaxAvailableHeight(
+            @NonNull View anchor, int yOffset, boolean ignoreBottomDecorations) {
         final Rect displayFrame = new Rect();
         anchor.getWindowVisibleDisplayFrame(displayFrame);
 
         final int[] anchorPos = mDrawingLocation;
         anchor.getLocationOnScreen(anchorPos);
 
-        int bottomEdge = displayFrame.bottom;
+        final int bottomEdge;
         if (ignoreBottomDecorations) {
-            Resources res = anchor.getContext().getResources();
+            final Resources res = anchor.getContext().getResources();
             bottomEdge = res.getDisplayMetrics().heightPixels;
+        } else {
+            bottomEdge = displayFrame.bottom;
         }
-        final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
+
+        final int distanceToBottom;
+        if (mOverlapAnchor) {
+            distanceToBottom = bottomEdge - anchorPos[1] - yOffset;
+        } else {
+            distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
+        }
         final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
 
         // anchorPos[1] is distance from anchor to top of screen
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index 7ca3339..ca1b211 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -31,6 +31,7 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Bitmap;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
@@ -55,6 +56,8 @@
 import android.widget.AdapterView.OnItemClickListener;
 import libcore.util.Objects;
 
+import com.android.internal.R;
+
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
@@ -206,14 +209,22 @@
 
     /** @hide */
     public static class OnClickHandler {
+
+        private int mEnterAnimationId;
+
         public boolean onClickHandler(View view, PendingIntent pendingIntent,
                 Intent fillInIntent) {
             try {
                 // TODO: Unregister this handler if PendingIntent.FLAG_ONE_SHOT?
                 Context context = view.getContext();
-                ActivityOptions opts = ActivityOptions.makeScaleUpAnimation(view,
-                        0, 0,
-                        view.getMeasuredWidth(), view.getMeasuredHeight());
+                ActivityOptions opts;
+                if (mEnterAnimationId != 0) {
+                    opts = ActivityOptions.makeCustomAnimation(context, mEnterAnimationId, 0);
+                } else {
+                    opts = ActivityOptions.makeScaleUpAnimation(view,
+                            0, 0,
+                            view.getMeasuredWidth(), view.getMeasuredHeight());
+                }
                 context.startIntentSender(
                         pendingIntent.getIntentSender(), fillInIntent,
                         Intent.FLAG_ACTIVITY_NEW_TASK,
@@ -228,6 +239,10 @@
             }
             return true;
         }
+
+        public void setEnterAnimationId(int enterAnimationId) {
+            mEnterAnimationId = enterAnimationId;
+        }
     }
 
     /**
@@ -2761,11 +2776,31 @@
         inflater.setFilter(this);
         result = inflater.inflate(rvToApply.getLayoutId(), parent, false);
 
+        loadTransitionOverride(context, handler);
+
         rvToApply.performApply(result, parent, handler);
 
         return result;
     }
 
+    private static void loadTransitionOverride(Context context,
+            RemoteViews.OnClickHandler handler) {
+        if (handler != null && context.getResources().getBoolean(
+                com.android.internal.R.bool.config_overrideRemoteViewsActivityTransition)) {
+            TypedArray windowStyle = context.getTheme().obtainStyledAttributes(
+                    com.android.internal.R.styleable.Window);
+            int windowAnimations = windowStyle.getResourceId(
+                    com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
+            TypedArray windowAnimationStyle = context.obtainStyledAttributes(
+                    windowAnimations, com.android.internal.R.styleable.WindowAnimation);
+            handler.setEnterAnimationId(windowAnimationStyle.getResourceId(
+                    com.android.internal.R.styleable.
+                            WindowAnimation_activityOpenRemoteViewsEnterAnimation, 0));
+            windowStyle.recycle();
+            windowAnimationStyle.recycle();
+        }
+    }
+
     /**
      * Applies all of the actions to the provided view.
      *
diff --git a/core/java/android/widget/Switch.java b/core/java/android/widget/Switch.java
index 6f3a711..434516d 100644
--- a/core/java/android/widget/Switch.java
+++ b/core/java/android/widget/Switch.java
@@ -1387,7 +1387,7 @@
             mTrackDrawable.jumpToCurrentState();
         }
 
-        if (mPositionAnimator != null && mPositionAnimator.isRunning()) {
+        if (mPositionAnimator != null && mPositionAnimator.isStarted()) {
             mPositionAnimator.end();
             mPositionAnimator = null;
         }
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 2172b5c..f0e216f 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -40,6 +40,7 @@
 import android.os.ResultReceiver;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.DocumentsContract;
 import android.service.chooser.ChooserTarget;
 import android.service.chooser.ChooserTargetService;
 import android.service.chooser.IChooserTargetResult;
@@ -269,7 +270,20 @@
     }
 
     @Override
-    boolean shouldAutoLaunchSingleChoice() {
+    boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
+        final Intent intent = target.getResolvedIntent();
+        final ResolveInfo resolve = target.getResolveInfo();
+
+        // When GET_CONTENT is handled by the DocumentsUI system component,
+        // we're okay automatically launching it, since it offers it's own
+        // intent disambiguation UI.
+        if (intent != null && Intent.ACTION_GET_CONTENT.equals(intent.getAction())
+                && resolve != null && resolve.priority > 0
+                && resolve.activityInfo != null && DocumentsContract.PACKAGE_DOCUMENTS_UI
+                        .equals(resolve.activityInfo.packageName)) {
+            return true;
+        }
+
         return false;
     }
 
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index ef9d1ce..1710489 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -796,7 +796,7 @@
         return false;
     }
 
-    boolean shouldAutoLaunchSingleChoice() {
+    boolean shouldAutoLaunchSingleChoice(TargetInfo target) {
         return true;
     }
 
@@ -837,18 +837,21 @@
         mAlwaysUseOption = alwaysUseOption;
 
         int count = mAdapter.getUnfilteredCount();
-        if ((!shouldAutoLaunchSingleChoice() && count > 0)
-                || count > 1
-                || (count == 1 && mAdapter.getOtherProfile() != null)) {
+        if (count == 1 && mAdapter.getOtherProfile() == null) {
+            // Only one target, so we're a candidate to auto-launch!
+            final TargetInfo target = mAdapter.targetInfoForPosition(0, false);
+            if (shouldAutoLaunchSingleChoice(target)) {
+                safelyStartActivity(target);
+                mPackageMonitor.unregister();
+                mRegistered = false;
+                finish();
+                return true;
+            }
+        }
+        if (count > 0) {
             setContentView(layoutId);
             mAdapterView = (AbsListView) findViewById(R.id.resolver_list);
             onPrepareAdapterView(mAdapterView, mAdapter, alwaysUseOption);
-        } else if (count == 1) {
-            safelyStartActivity(mAdapter.targetInfoForPosition(0, false));
-            mPackageMonitor.unregister();
-            mRegistered = false;
-            finish();
-            return true;
         } else {
             setContentView(R.layout.resolver_list);
 
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index b6240e4..c25db65 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -46,6 +46,9 @@
     public static final int ACTION_FINGERPRINT_RENAME = 254;
     public static final int ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE = 255;
     public static final int ACTION_WIGGLE_CAMERA_GESTURE = 256;
+    public static final int QS_LOCK_TILE = 257;
+    public static final int QS_USER_TILE = 258;
+    public static final int QS_BATTERY_TILE = 259;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index e39bf607..64b7768 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -105,7 +105,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 131 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 132 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -5704,6 +5704,8 @@
                                 cpuSpeeds[speed] = new LongSamplingCounter(mOnBatteryTimeBase, in);
                             }
                         }
+                    } else {
+                        mCpuClusterSpeed[cluster] = null;
                     }
                 }
             } else {
@@ -9382,13 +9384,14 @@
 
                 u.mCpuClusterSpeed = new LongSamplingCounter[numClusters][];
                 for (int cluster = 0; cluster < numClusters; cluster++) {
-                    int NSB = in.readInt();
-                    if (mPowerProfile != null &&
-                            mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
-                        throw new ParcelFormatException("File corrupt: too many speed bins " + NSB);
-                    }
-
                     if (in.readInt() != 0) {
+                        final int NSB = in.readInt();
+                        if (mPowerProfile != null &&
+                                mPowerProfile.getNumSpeedStepsInCpuCluster(cluster) != NSB) {
+                            throw new ParcelFormatException("File corrupt: too many speed bins " +
+                                    NSB);
+                        }
+
                         u.mCpuClusterSpeed[cluster] = new LongSamplingCounter[NSB];
                         for (int speed = 0; speed < NSB; speed++) {
                             if (in.readInt() != 0) {
@@ -9397,6 +9400,8 @@
                                 u.mCpuClusterSpeed[cluster][speed].readSummaryFromParcelLocked(in);
                             }
                         }
+                    } else {
+                        u.mCpuClusterSpeed[cluster] = null;
                     }
                 }
             } else {
diff --git a/core/java/com/android/internal/os/InstallerConnection.java b/core/java/com/android/internal/os/InstallerConnection.java
index db2b41f..13d046e 100644
--- a/core/java/com/android/internal/os/InstallerConnection.java
+++ b/core/java/com/android/internal/os/InstallerConnection.java
@@ -20,6 +20,7 @@
 import android.net.LocalSocketAddress;
 import android.os.SystemClock;
 import android.util.Slog;
+
 import libcore.io.IoUtils;
 import libcore.io.Streams;
 
@@ -91,32 +92,29 @@
         }
     }
 
-    public int dexopt(String apkPath, int uid, boolean isPublic,
-            String instructionSet, int dexoptNeeded, boolean bootComplete) {
-        return dexopt(apkPath, uid, isPublic, "*", instructionSet, dexoptNeeded,
-                false, false, null, bootComplete);
+    public int dexopt(String apkPath, int uid, String instructionSet,
+            int dexoptNeeded, int dexFlags) {
+        return dexopt(apkPath, uid, "*", instructionSet, dexoptNeeded,
+                null /*outputPath*/, dexFlags);
     }
 
-    public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, int dexoptNeeded, boolean vmSafeMode,
-            boolean debuggable, String outputPath, boolean bootComplete) {
+    public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+            int dexoptNeeded, String outputPath, int dexFlags) {
         StringBuilder builder = new StringBuilder("dexopt");
         builder.append(' ');
         builder.append(apkPath);
         builder.append(' ');
         builder.append(uid);
-        builder.append(isPublic ? " 1" : " 0");
         builder.append(' ');
         builder.append(pkgName);
         builder.append(' ');
         builder.append(instructionSet);
         builder.append(' ');
         builder.append(dexoptNeeded);
-        builder.append(vmSafeMode ? " 1" : " 0");
-        builder.append(debuggable ? " 1" : " 0");
         builder.append(' ');
         builder.append(outputPath != null ? outputPath : "!");
-        builder.append(bootComplete ? " 1" : " 0");
+        builder.append(' ');
+        builder.append(dexFlags);
         return execute(builder.toString());
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index eee8b08..aaa89df 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -486,8 +486,8 @@
                 final int dexoptNeeded = DexFile.getDexOptNeeded(
                         classPathElement, "*", instructionSet, false /* defer */);
                 if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                    installer.dexopt(classPathElement, Process.SYSTEM_UID, false,
-                            instructionSet, dexoptNeeded, false /* boot complete */);
+                    installer.dexopt(classPathElement, Process.SYSTEM_UID, instructionSet,
+                            dexoptNeeded, 0 /*dexFlags*/);
                 }
             }
         } catch (IOException ioe) {
diff --git a/core/java/com/android/internal/policy/DecorContext.java b/core/java/com/android/internal/policy/DecorContext.java
new file mode 100644
index 0000000..4f17c39
--- /dev/null
+++ b/core/java/com/android/internal/policy/DecorContext.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.view.ContextThemeWrapper;
+import android.view.WindowManager;
+import android.view.WindowManagerImpl;
+
+/**
+ * Context for decor views which can be seeded with pure application context and not depend on the
+ * activity, but still provide some of the facilities that Activity has, e.g. themes.
+ *
+ * @hide
+ */
+class DecorContext extends ContextThemeWrapper {
+    private PhoneWindow mPhoneWindow;
+    private WindowManager mWindowManager;
+
+    public DecorContext(Context context) {
+        super(context, null);
+    }
+
+    void setPhoneWindow(PhoneWindow phoneWindow) {
+        mPhoneWindow = phoneWindow;
+        mWindowManager = null;
+    }
+
+    @Override
+    public Object getSystemService(String name) {
+        if (Context.WINDOW_SERVICE.equals(name)) {
+            if (mWindowManager == null) {
+                WindowManagerImpl wm =
+                        (WindowManagerImpl) super.getSystemService(Context.WINDOW_SERVICE);
+                mWindowManager = wm.createLocalWindowManager(mPhoneWindow);
+            }
+            return mWindowManager;
+        }
+        return super.getSystemService(name);
+    }
+}
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index ec41447..b6d7364 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -32,6 +32,8 @@
 import android.animation.ObjectAnimator;
 import android.app.ActivityManagerNative;
 import android.app.SearchManager;
+import android.content.ContextWrapper;
+import android.content.res.Resources;
 import android.os.Build;
 import android.os.UserHandle;
 
@@ -71,6 +73,7 @@
 import com.android.internal.view.menu.ListMenuPresenter;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuDialogHelper;
+import com.android.internal.view.menu.MenuPopupHelper;
 import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.view.menu.MenuView;
 import com.android.internal.widget.ActionBarContextView;
@@ -274,6 +277,7 @@
 
     private ContextMenuBuilder mContextMenu;
     private MenuDialogHelper mContextMenuHelper;
+    private MenuPopupHelper mContextMenuPopupHelper;
     private boolean mClosingActionMenu;
 
     private int mVolumeControlStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
@@ -315,6 +319,7 @@
     private Rect mOutsets = new Rect();
 
     private boolean mIsStartingWindow;
+    private int mTheme = -1;
 
     static class WindowManagerHolder {
         static final IWindowManager sWindowManager = IWindowManager.Stub.asInterface(
@@ -335,6 +340,10 @@
             mElevation = preservedWindow.getElevation();
             mLoadEleveation = false;
             mForceDecorInstall = true;
+            // If we're preserving window, carry over the app token from the preserved
+            // window, as we'll be skipping the addView in handleResumeActivity(), and
+            // the token will not be updated as for a new window.
+            getAttributes().token = preservedWindow.getAttributes().token;
         }
     }
 
@@ -1123,6 +1132,10 @@
             mContextMenuHelper.dismiss();
             mContextMenuHelper = null;
         }
+        if (mContextMenuPopupHelper != null) {
+            mContextMenuPopupHelper.dismiss();
+            mContextMenuPopupHelper = null;
+        }
     }
 
     @Override
@@ -2850,6 +2863,29 @@
         }
 
         @Override
+        public boolean showContextMenuForChild(View originalView, float x, float y) {
+            // Reuse the context menu builder
+            if (mWindow.mContextMenu == null) {
+                mWindow.mContextMenu = new ContextMenuBuilder(getContext());
+                mWindow.mContextMenu.setCallback(mWindow.mContextMenuCallback);
+            } else {
+                mWindow.mContextMenu.clearAll();
+            }
+
+            final MenuPopupHelper helper = mWindow.mContextMenu.showPopup(
+                    getContext(), originalView, x, y);
+            if (helper != null) {
+                helper.setCallback(mWindow.mContextMenuCallback);
+            } else if (mWindow.mContextMenuPopupHelper != null) {
+                // No menu to show, but if we have a menu currently showing it just became blank.
+                // Close it.
+                mWindow.mContextMenuPopupHelper.dismiss();
+            }
+            mWindow.mContextMenuPopupHelper = helper;
+            return helper != null;
+        }
+
+        @Override
         public ActionMode startActionModeForChild(View originalView,
                 ActionMode.Callback callback) {
             return startActionModeForChild(originalView, callback, ActionMode.TYPE_PRIMARY);
@@ -3674,6 +3710,11 @@
 
         void setWindow(PhoneWindow phoneWindow) {
             mWindow = phoneWindow;
+            Context context = getContext();
+            if (context instanceof DecorContext) {
+                DecorContext decorContex = (DecorContext) context;
+                decorContex.setPhoneWindow(mWindow);
+            }
         }
 
         /**
@@ -3789,9 +3830,15 @@
         // System process doesn't have application context and in that case we need to directly use
         // the context we have. Otherwise we want the application context, so we don't cling to the
         // activity.
-        Context context = getContext().getApplicationContext();
-        if (context == null) {
+        Context applicationContext = getContext().getApplicationContext();
+        Context context;
+        if (applicationContext == null) {
             context = getContext();
+        } else {
+            context = new DecorContext(applicationContext);
+            if (mTheme != -1) {
+                context.setTheme(mTheme);
+            }
         }
         return new DecorView(context, featureId);
     }
@@ -4162,14 +4209,10 @@
             // Dependent on the brightness of the used title we either use the
             // dark or the light button frame.
             if (nonClientDecorView == null) {
+                Context context = mDecor.getContext();
                 TypedValue value = new TypedValue();
-                getContext().getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
-                // We can't use the application context inside the general inflater, because some
-                // views might depend on the fact that they get Activity or even specific activity.
-                // We control the NonClientDecor, so we know that application context should be
-                // safe enough.
-                LayoutInflater inflater =
-                        mLayoutInflater.cloneInContext(getContext().getApplicationContext());
+                context.getTheme().resolveAttribute(R.attr.colorPrimary, value, true);
+                LayoutInflater inflater = mLayoutInflater.from(context);
                 if (Color.luminance(value.data) < 0.5) {
                     nonClientDecorView = (NonClientDecorView) inflater.inflate(
                             R.layout.non_client_decor_dark, null);
@@ -4202,8 +4245,9 @@
             if (!mInvalidatePanelMenuPosted && mInvalidatePanelMenuFeatures != 0) {
                 mDecor.postOnAnimation(mInvalidatePanelMenuRunnable);
             }
+        } else {
+            mDecor.setWindow(this);
         }
-        mDecor.setWindow(this);
         if (mContentParent == null) {
             mContentParent = generateLayout(mDecor);
 
@@ -5377,4 +5421,15 @@
     public boolean hasNonClientDecorView() {
         return mNonClientDecorView != null;
     }
+
+    @Override
+    public void setTheme(int resid) {
+        mTheme = resid;
+        if (mDecor != null) {
+            Context context = mDecor.getContext();
+            if (context instanceof DecorContext) {
+                context.setTheme(resid);
+            }
+        }
+    }
 }
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index ab3ec98..11ef18b 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -74,7 +74,9 @@
 
     /**
      * Notifies the status bar that a camera launch gesture has been detected.
+     *
+     * @param source the identifier for the gesture, see {@link StatusBarManager}
      */
-    void onCameraLaunchGestureDetected();
+    void onCameraLaunchGestureDetected(int source);
 }
 
diff --git a/core/java/com/android/internal/view/FloatingActionMode.java b/core/java/com/android/internal/view/FloatingActionMode.java
index 44df0ce..b44baa2 100644
--- a/core/java/com/android/internal/view/FloatingActionMode.java
+++ b/core/java/com/android/internal/view/FloatingActionMode.java
@@ -35,7 +35,7 @@
 public class FloatingActionMode extends ActionMode {
 
     private static final int MAX_HIDE_DURATION = 3000;
-    private static final int MOVING_HIDE_DELAY = 300;
+    private static final int MOVING_HIDE_DELAY = 50;
 
     private final Context mContext;
     private final ActionMode.Callback2 mCallback;
@@ -181,7 +181,6 @@
                 // Content rect is moving.
                 mOriginatingView.removeCallbacks(mMovingOff);
                 mFloatingToolbarVisibilityHelper.setMoving(true);
-                mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
                 mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
 
                 mFloatingToolbar.setContentRect(mContentRectOnScreen);
@@ -189,9 +188,9 @@
             }
         } else {
             mFloatingToolbarVisibilityHelper.setOutOfBounds(true);
-            mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
             mContentRectOnScreen.setEmpty();
         }
+        mFloatingToolbarVisibilityHelper.updateToolbarVisibility();
 
         mPreviousContentRectOnScreen.set(mContentRectOnScreen);
     }
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 415f325..293e2ad 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -20,14 +20,16 @@
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
-import android.widget.AdapterView;
 import android.widget.DropDownListView;
+import android.widget.FrameLayout;
 import android.widget.MenuItemHoverListener;
+import android.widget.ListAdapter;
 import android.widget.ListView;
 import android.widget.MenuPopupWindow;
 import android.widget.MenuPopupWindow.MenuDropDownListView;
 import android.widget.PopupWindow;
 import android.widget.PopupWindow.OnDismissListener;
+import android.widget.TextView;
 
 import com.android.internal.util.Preconditions;
 
@@ -36,8 +38,8 @@
  * side.
  * @hide
  */
-final class CascadingMenuPopup extends MenuPopup implements AdapterView.OnItemClickListener,
-        MenuPresenter, OnKeyListener, PopupWindow.OnDismissListener {
+final class CascadingMenuPopup extends MenuPopup implements MenuPresenter, OnKeyListener,
+        PopupWindow.OnDismissListener {
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({HORIZ_POSITION_LEFT, HORIZ_POSITION_RIGHT})
     public @interface HorizPosition {}
@@ -96,7 +98,7 @@
             int menuIndex = -1;
             for (int i = 0; i < mListViews.size(); i++) {
                 final MenuDropDownListView view = (MenuDropDownListView) mListViews.get(i);
-                final MenuAdapter adapter = (MenuAdapter) view.getAdapter();
+                final MenuAdapter adapter = toMenuAdapter(view.getAdapter());
 
                 if (adapter.getAdapterMenu() == menu) {
                     menuIndex = i;
@@ -129,7 +131,7 @@
                             int nextIndex = mListViews.indexOf(view) + 1;
                             if (nextIndex < mListViews.size()) {
                                 MenuAdapter nextSubMenuAdapter =
-                                        (MenuAdapter) mListViews.get(nextIndex).getAdapter();
+                                        toMenuAdapter(mListViews.get(nextIndex).getAdapter());
                                 // Disable exit animation, to prevent overlapping fading out
                                 // submenus.
                                 mPopupWindows.get(nextIndex).setExitTransition(null);
@@ -151,9 +153,7 @@
 
                 final MenuDropDownListView nextView =
                         (MenuDropDownListView) mListViews.get(menuIndex + 1);
-                final MenuAdapter nextAdapter = (MenuAdapter) nextView.getAdapter();
-
-                view.clearSelection();
+                final MenuAdapter nextAdapter = toMenuAdapter(nextView.getAdapter());
 
                 mSubMenuHoverHandler.removeCallbacksAndMessages(null);
                 mSubMenuHoverHandler.postDelayed(new Runnable() {
@@ -162,9 +162,14 @@
                         // Make sure the menu wasn't already closed by something else and that
                         // it wasn't re-hovered by the user since this was scheduled.
                         int nextMenuIndex = mListViews.indexOf(nextView);
+
                         if (nextMenuIndex != -1 && nextView.getSelectedView() == null) {
                             // Disable exit animation, to prevent overlapping fading out submenus.
-                            mPopupWindows.get(nextMenuIndex).setExitTransition(null);
+                            for (int i = nextMenuIndex; i < mPopupWindows.size(); i++) {
+                                final MenuPopupWindow popupWindow = mPopupWindows.get(i);
+                                popupWindow.setExitTransition(null);
+                                popupWindow.setAnimationStyle(0);
+                            }
                             nextAdapter.getAdapterMenu().close();
                         }
                     }
@@ -178,9 +183,13 @@
     private View mShownAnchorView;
     private List<DropDownListView> mListViews;
     private List<MenuPopupWindow> mPopupWindows;
+    private int mLastPosition;
+    private List<Integer> mPositions;
     private List<int[]> mOffsets;
-    private int mPreferredPosition;
+    private int mInitXOffset;
+    private int mInitYOffset;
     private boolean mForceShowIcon;
+    private boolean mShowTitle;
     private Callback mPresenterCallback;
     private ViewTreeObserver mTreeObserver;
     private PopupWindow.OnDismissListener mOnDismissListener;
@@ -203,14 +212,14 @@
         final Resources res = context.getResources();
         final Configuration config = res.getConfiguration();
         mLayoutDirection = config.getLayoutDirection();
-        mPreferredPosition = mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
-                HORIZ_POSITION_RIGHT;
+        mLastPosition = getInitialMenuPosition();
         mMenuMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
                 res.getDimensionPixelSize(com.android.internal.R.dimen.config_prefDialogWidth));
 
         mPopupWindows = new ArrayList<MenuPopupWindow>();
         mListViews = new ArrayList<DropDownListView>();
         mOffsets = new ArrayList<int[]>();
+        mPositions = new ArrayList<Integer>();
         mSubMenuHoverHandler = new Handler();
     }
 
@@ -244,7 +253,25 @@
         for (int i = 0; i < mPopupWindows.size(); i++) {
             MenuPopupWindow popupWindow = mPopupWindows.get(i);
             popupWindow.show();
-            mListViews.add((DropDownListView) popupWindow.getListView());
+            DropDownListView listView = (DropDownListView) popupWindow.getListView();
+            mListViews.add(listView);
+
+            MenuBuilder menu = toMenuAdapter(listView.getAdapter()).getAdapterMenu();
+            if (i == 0 && mShowTitle && menu.getHeaderTitle() != null) {
+                FrameLayout titleItemView =
+                        (FrameLayout) LayoutInflater.from(mContext).inflate(
+                                com.android.internal.R.layout.popup_menu_header_item_layout,
+                                listView,
+                                false);
+                TextView titleView = (TextView) titleItemView.findViewById(
+                        com.android.internal.R.id.title);
+                titleView.setText(menu.getHeaderTitle());
+                titleItemView.setEnabled(false);
+                listView.addHeaderView(titleItemView, null, false);
+
+                // Update to show the title.
+                popupWindow.show();
+            }
         }
 
         mShownAnchorView = mAnchorView;
@@ -271,12 +298,6 @@
     }
 
     @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        MenuAdapter adapter = (MenuAdapter) parent.getAdapter();
-        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
-    }
-
-    @Override
     public boolean onKey(View v, int keyCode, KeyEvent event) {
         if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
             dismiss();
@@ -286,6 +307,16 @@
     }
 
     /**
+     * Determines the proper initial menu position for the current LTR/RTL configuration.
+     * @return The initial position.
+     */
+    @HorizPosition
+    private int getInitialMenuPosition() {
+        return mLayoutDirection == View.LAYOUT_DIRECTION_RTL ? HORIZ_POSITION_LEFT :
+                HORIZ_POSITION_RIGHT;
+    }
+
+    /**
      * Determines whether the next submenu (of the given width) should display on the right or on
      * the left of the most recent menu.
      *
@@ -302,7 +333,7 @@
         final Rect displayFrame = new Rect();
         mShownAnchorView.getWindowVisibleDisplayFrame(displayFrame);
 
-        if (mPreferredPosition == HORIZ_POSITION_RIGHT) {
+        if (mLastPosition == HORIZ_POSITION_RIGHT) {
             final int right = screenLocation[0] + lastListView.getWidth() + nextMenuWidth;
             if (right > displayFrame.right) {
                 return HORIZ_POSITION_LEFT;
@@ -342,7 +373,7 @@
             ListView lastListView = mListViews.get(mListViews.size() - 1);
             @HorizPosition int nextMenuPosition = getNextMenuPosition(menuWidth);
             boolean showOnRight = nextMenuPosition == HORIZ_POSITION_RIGHT;
-            mPreferredPosition = nextMenuPosition;
+            mLastPosition = nextMenuPosition;
 
             int[] lastLocation = new int[2];
             lastListView.getLocationOnScreen(lastLocation);
@@ -367,6 +398,9 @@
 
             y = lastOffset[1] + lastListView.getSelectedView().getTop() -
                     lastListView.getChildAt(0).getTop();
+        } else {
+            x = mInitXOffset;
+            y = mInitYOffset;
         }
 
         popupWindow.setWidth(menuWidth);
@@ -379,11 +413,13 @@
         // we deliberately do not yet show the popupWindow, as #show() will do that later.
         if (isShowing()) {
             popupWindow.show();
-            mListViews.add((DropDownListView) popupWindow.getListView());
+            DropDownListView listView = (DropDownListView) popupWindow.getListView();
+            mListViews.add(listView);
         }
 
         int[] offsets = {x, y};
         mOffsets.add(offsets);
+        mPositions.add(mLastPosition);
     }
 
     /**
@@ -410,8 +446,9 @@
         if (dismissedIndex != -1) {
             for (int i = dismissedIndex; i < mListViews.size(); i++) {
                 ListView view = mListViews.get(i);
-                MenuAdapter adapter = (MenuAdapter) view.getAdapter();
-                adapter.mAdapterMenu.close();
+                ListAdapter adapter = view.getAdapter();
+                MenuAdapter menuAdapter = toMenuAdapter(adapter);
+                menuAdapter.mAdapterMenu.close();
             }
         }
     }
@@ -419,7 +456,7 @@
     @Override
     public void updateMenuView(boolean cleared) {
         for (ListView view : mListViews) {
-            ((MenuAdapter) view.getAdapter()).notifyDataSetChanged();
+            toMenuAdapter(view.getAdapter()).notifyDataSetChanged();
         }
     }
 
@@ -432,7 +469,7 @@
     public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
         // Don't allow double-opening of the same submenu.
         for (ListView view : mListViews) {
-            if (((MenuAdapter) view.getAdapter()).mAdapterMenu.equals(subMenu)) {
+            if (toMenuAdapter(view.getAdapter()).mAdapterMenu.equals(subMenu)) {
                 // Just re-focus that one.
                 view.requestFocus();
                 return true;
@@ -456,7 +493,7 @@
 
         for (int i = 0; i < mListViews.size(); i++) {
             ListView view = mListViews.get(i);
-            MenuAdapter adapter = (MenuAdapter) view.getAdapter();
+            MenuAdapter adapter = toMenuAdapter(view.getAdapter());
 
             if (menuIndex == -1 && menu == adapter.mAdapterMenu) {
                 menuIndex = i;
@@ -479,9 +516,11 @@
             mListViews.subList(menuIndex, mListViews.size()).clear();
             mOffsets.subList(menuIndex, mOffsets.size()).clear();
 
-            // If there's still a menu open, refocus the new leaf [sub]menu.
-            if (mListViews.size() > 0) {
-                mListViews.get(mListViews.size() - 1).requestFocus();
+            mPositions.subList(menuIndex, mPositions.size()).clear();
+            if (mPositions.size() > 0) {
+                mLastPosition = mPositions.get(mPositions.size() - 1);
+            } else {
+                mLastPosition = getInitialMenuPosition();
             }
         }
 
@@ -540,4 +579,18 @@
         return mListViews.size() > 0 ? mListViews.get(mListViews.size() - 1) : null;
     }
 
+    @Override
+    public void setHorizontalOffset(int x) {
+        mInitXOffset = x;
+    }
+
+    @Override
+    public void setVerticalOffset(int y) {
+        mInitYOffset = y;
+    }
+
+    @Override
+    public void setShowTitle(boolean showTitle) {
+        mShowTitle = showTitle;
+    }
 }
\ No newline at end of file
diff --git a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
index bf44d51..aaa1bf16 100644
--- a/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/ContextMenuBuilder.java
@@ -17,6 +17,7 @@
 package com.android.internal.view.menu;
 
 import android.content.Context;
+import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
 import android.os.IBinder;
 import android.util.EventLog;
@@ -93,4 +94,29 @@
         return null;
     }
     
+    public MenuPopupHelper showPopup(Context context, View originalView, float x, float y) {
+        if (originalView != null) {
+            // Let relevant views and their populate context listeners populate
+            // the context menu
+            originalView.createContextMenu(this);
+        }
+
+        if (getVisibleItems().size() > 0) {
+            EventLog.writeEvent(50001, 1);
+
+            int location[] = new int[2];
+            originalView.getLocationOnScreen(location);
+
+            final MenuPopupHelper helper = new MenuPopupHelper(
+                    context,
+                    this,
+                    originalView,
+                    false /* overflowOnly */,
+                    com.android.internal.R.attr.contextPopupMenuStyle);
+            helper.show(Math.round(x), Math.round(y));
+            return helper;
+        }
+
+        return null;
+    }
 }
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index b43e8ad..98f5d90 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -17,10 +17,13 @@
 package com.android.internal.view.menu;
 
 import android.content.Context;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.View.MeasureSpec;
 import android.view.ViewGroup;
+import android.widget.AdapterView;
 import android.widget.FrameLayout;
+import android.widget.HeaderViewListAdapter;
 import android.widget.ListAdapter;
 import android.widget.PopupWindow;
 
@@ -30,7 +33,8 @@
  *
  * @hide
  */
-public abstract class MenuPopup implements ShowableListMenu, MenuPresenter {
+public abstract class MenuPopup implements ShowableListMenu, MenuPresenter,
+        AdapterView.OnItemClickListener {
 
     public abstract void setForceShowIcon(boolean forceShow);
 
@@ -49,6 +53,18 @@
 
     public abstract void setAnchorView(View anchor);
 
+    public abstract void setHorizontalOffset(int x);
+
+    public abstract void setVerticalOffset(int y);
+
+    /**
+     * Set whether a title entry should be shown in the popup menu (if a title exists for the
+     * menu).
+     *
+     * @param showTitle
+     */
+    public abstract void setShowTitle(boolean showTitle);
+
     /**
      * Set a listener to receive a callback when the popup is dismissed.
      *
@@ -81,6 +97,16 @@
         return 0;
     }
 
+    @Override
+    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+        ListAdapter outerAdapter = (ListAdapter) parent.getAdapter();
+        MenuAdapter wrappedAdapter = toMenuAdapter(outerAdapter);
+
+        // Use the position from the outer adapter so that if a header view was added, we don't get
+        // an off-by-1 error in position.
+        wrappedAdapter.mAdapterMenu.performItemAction((MenuItem) outerAdapter.getItem(position), 0);
+    }
+
     /**
      * Measures the width of the given menu view.
      *
@@ -121,4 +147,19 @@
 
         return maxWidth;
     }
-}
\ No newline at end of file
+
+    /**
+     * Converts the given ListAdapter originating from a menu, to a MenuAdapter, accounting for
+     * the possibility of the parameter adapter actually wrapping the MenuAdapter. (That could
+     * happen if a header view was added on the menu.)
+     *
+     * @param adapter
+     * @return
+     */
+    protected static MenuAdapter toMenuAdapter(ListAdapter adapter) {
+        if (adapter instanceof HeaderViewListAdapter) {
+            return (MenuAdapter) ((HeaderViewListAdapter) adapter).getWrappedAdapter();
+        }
+        return (MenuAdapter) adapter;
+    }
+}
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
index ea79983..e674ecc 100644
--- a/core/java/com/android/internal/view/menu/MenuPopupHelper.java
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -39,7 +39,11 @@
     private MenuPopup mPopup;
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
+    private boolean mForceShowIcon;
+    private boolean mShowTitle;
     private Callback mPresenterCallback;
+    private int mInitXOffset;
+    private int mInitYOffset;
 
     public MenuPopupHelper(Context context, MenuBuilder menu) {
         this(context, menu, null, false, com.android.internal.R.attr.popupMenuStyle, 0);
@@ -81,6 +85,7 @@
     }
 
     public void setForceShowIcon(boolean forceShow) {
+        mForceShowIcon = forceShow;
         mPopup.setForceShowIcon(forceShow);
     }
 
@@ -99,6 +104,12 @@
         }
     }
 
+    public void show(int x, int y) {
+        if (!tryShow(x, y)) {
+            throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
+        }
+    }
+
     public ShowableListMenu getPopup() {
         return mPopup;
     }
@@ -118,10 +129,40 @@
             return false;
         }
 
+        mInitXOffset = 0;
+        mInitYOffset = 0;
+        mShowTitle = false;
+
+        showPopup();
+        return true;
+    }
+
+    public boolean tryShow(int x, int y) {
+        if (isShowing()) {
+            return true;
+        }
+
+        if (mAnchorView == null) {
+            return false;
+        }
+
+        mInitXOffset = x;
+        mInitYOffset = y;
+        mShowTitle = true;
+
+        showPopup();
+        return true;
+    }
+
+    private void showPopup() {
         mPopup = createMenuPopup();
         mPopup.setAnchorView(mAnchorView);
-        mPopup.setGravity(mDropDownGravity);
         mPopup.setCallback(mPresenterCallback);
+        mPopup.setForceShowIcon(mForceShowIcon);
+        mPopup.setGravity(mDropDownGravity);
+        mPopup.setHorizontalOffset(mInitXOffset);
+        mPopup.setShowTitle(mShowTitle);
+        mPopup.setVerticalOffset(mInitYOffset);
 
         // In order for subclasses of MenuPopupHelper to satisfy the OnDismissedListener interface,
         // we must set the listener to this outer Helper rather than to the inner MenuPopup.
@@ -131,7 +172,6 @@
 
         mPopup.addMenu(mMenu);
         mPopup.show();
-        return true;
     }
 
     public void dismiss() {
@@ -149,7 +189,6 @@
         return mPopup != null && mPopup.isShowing();
     }
 
-
     public void setCallback(MenuPresenter.Callback cb) {
         mPresenterCallback = cb;
         mPopup.setCallback(cb);
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 8877f3d..caee0d2 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -6,17 +6,17 @@
 import android.view.Gravity;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
-import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.View.OnAttachStateChangeListener;
 import android.view.View.OnKeyListener;
 import android.view.ViewTreeObserver.OnGlobalLayoutListener;
 import android.view.ViewTreeObserver;
-import android.widget.AdapterView;
+import android.widget.FrameLayout;
 import android.widget.ListView;
 import android.widget.MenuPopupWindow;
 import android.widget.PopupWindow;
+import android.widget.TextView;
 import android.widget.AdapterView.OnItemClickListener;
 import android.widget.PopupWindow.OnDismissListener;
 
@@ -92,6 +92,10 @@
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
+    private int mXOffset;
+    private int mYOffset;
+    private boolean mShowTitle;
+
     public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
             int popupStyleRes, boolean overflowOnly) {
         mContext = Preconditions.checkNotNull(context);
@@ -158,8 +162,28 @@
 
         mPopup.setContentWidth(mContentWidth);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
+        mPopup.setHorizontalOffset(mXOffset);
+        mPopup.setVerticalOffset(mYOffset);
         mPopup.show();
-        mPopup.getListView().setOnKeyListener(this);
+
+        ListView listView = mPopup.getListView();
+        listView.setOnKeyListener(this);
+
+        if (mShowTitle && mMenu.getHeaderTitle() != null) {
+            FrameLayout titleItemView =
+                    (FrameLayout) LayoutInflater.from(mContext).inflate(
+                            com.android.internal.R.layout.popup_menu_header_item_layout,
+                            listView,
+                            false);
+            TextView titleView = (TextView) titleItemView.findViewById(
+                    com.android.internal.R.id.title);
+            titleView.setText(mMenu.getHeaderTitle());
+            titleItemView.setEnabled(false);
+            listView.addHeaderView(titleItemView, null, false);
+
+            // Update to show the title.
+            mPopup.show();
+        }
         return true;
     }
 
@@ -178,12 +202,6 @@
     }
 
     @Override
-    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
-        MenuAdapter adapter = mAdapter;
-        adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
-    }
-
-    @Override
     public void addMenu(MenuBuilder menu) {
         // No-op: standard implementation has only one menu which is set in the constructor.
     }
@@ -288,4 +306,20 @@
     public ListView getListView() {
         return mPopup.getListView();
     }
-}
\ No newline at end of file
+
+
+    @Override
+    public void setHorizontalOffset(int x) {
+        mXOffset = x;
+    }
+
+    @Override
+    public void setVerticalOffset(int y) {
+        mYOffset = y;
+    }
+
+    @Override
+    public void setShowTitle(boolean showTitle) {
+        mShowTitle = showTitle;
+    }
+}
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index ca6fe61..7bab446 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -73,6 +73,8 @@
     // This class is responsible for the public API of the floating toolbar.
     // It delegates rendering operations to the FloatingToolbarPopup.
 
+    public static final String FLOATING_TOOLBAR_TAG = "floating_toolbar";
+
     private static final MenuItem.OnMenuItemClickListener NO_OP_MENUITEM_CLICK_LISTENER =
             new MenuItem.OnMenuItemClickListener() {
                 @Override
@@ -1460,8 +1462,10 @@
     }
 
     private static ViewGroup createContentContainer(Context context) {
-        return (ViewGroup) LayoutInflater.from(context)
+        ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
                 .inflate(R.layout.floating_popup_container, null);
+        contentContainer.setTag(FLOATING_TOOLBAR_TAG);
+        return contentContainer;
     }
 
     private static PopupWindow createPopupWindow(View content) {
@@ -1488,10 +1492,9 @@
     private static AnimatorSet createEnterAnimation(View view) {
         AnimatorSet animation =  new AnimatorSet();
         animation.playTogether(
-                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(200),
+                ObjectAnimator.ofFloat(view, View.ALPHA, 0, 1).setDuration(150),
                 // Make sure that view.x is always fixed throughout the duration of this animation.
                 ObjectAnimator.ofFloat(view, View.X, view.getX(), view.getX()));
-        animation.setStartDelay(50);
         return animation;
     }
 
@@ -1506,7 +1509,7 @@
             View view, int startDelay, Animator.AnimatorListener listener) {
         AnimatorSet animation =  new AnimatorSet();
         animation.playTogether(
-                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(200));
+                ObjectAnimator.ofFloat(view, View.ALPHA, 1, 0).setDuration(100));
         animation.setStartDelay(startDelay);
         animation.addListener(listener);
         return animation;
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index f7e9add..60ef4a4 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -1078,7 +1078,7 @@
         long deadline = getLong(LOCKOUT_ATTEMPT_DEADLINE, 0L, userId);
         final long timeoutMs = getLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0L, userId);
         final long now = SystemClock.elapsedRealtime();
-        if (deadline < now) {
+        if (deadline < now && deadline != 0) {
             // timeout expired
             setLong(LOCKOUT_ATTEMPT_DEADLINE, 0, userId);
             setLong(LOCKOUT_ATTEMPT_TIMEOUT_MS, 0, userId);
diff --git a/core/java/com/android/internal/widget/NonClientDecorView.java b/core/java/com/android/internal/widget/NonClientDecorView.java
index 6ab306c..56cf921 100644
--- a/core/java/com/android/internal/widget/NonClientDecorView.java
+++ b/core/java/com/android/internal/widget/NonClientDecorView.java
@@ -57,7 +57,8 @@
  * </ul>
  * This will be mitigated once b/22527834 will be addressed.
  */
-public class NonClientDecorView extends LinearLayout implements View.OnClickListener {
+public class NonClientDecorView extends LinearLayout
+        implements View.OnClickListener, View.OnTouchListener {
     private final static String TAG = "NonClientDecorView";
     // The height of a window which has focus in DIP.
     private final int DECOR_SHADOW_FOCUSED_HEIGHT_IN_DIP = 20;
@@ -112,7 +113,7 @@
     }
 
     @Override
-    public boolean onTouchEvent(MotionEvent e) {
+    public boolean onTouch(View v, MotionEvent e) {
         // Note: There are no mixed events. When a new device gets used (e.g. 1. Mouse, 2. touch)
         // the old input device events get cancelled first. So no need to remember the kind of
         // input device we are listening to.
@@ -224,6 +225,7 @@
         boolean invisible = isFillingScreen() || !mShowDecor;
         View caption = getChildAt(0);
         caption.setVisibility(invisible ? GONE : VISIBLE);
+        caption.setOnTouchListener(this);
         mVisible = !invisible;
     }
 
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 75da27e..20d00b0 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -1,6 +1,5 @@
 LOCAL_PATH:= $(call my-dir)
 include $(CLEAR_VARS)
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
 
 LOCAL_CFLAGS += -DHAVE_CONFIG_H -DKHTML_NO_EXCEPTIONS -DGKWQ_NO_JAVA
 LOCAL_CFLAGS += -DNO_SUPPORT_JS_BINDING -DQT_NO_WHEELEVENT -DKHTML_NO_XBL
@@ -259,6 +258,9 @@
 # <bionic_tls.h> in com_google_android_gles_jni_GLImpl.cpp
 LOCAL_C_INCLUDES += bionic/libc/private
 
+# AndroidRuntime.h depends on nativehelper/jni.h
+LOCAL_EXPORT_C_INCLUDE_DIRS := libnativehelper/include
+
 LOCAL_MODULE:= libandroid_runtime
 
 # -Wno-unknown-pragmas: necessary for Clang as the GL bindings need to turn
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index e4bc800..ffc69a9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -217,7 +217,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nativeFinishInit", "()V",
         (void*) com_android_internal_os_RuntimeInit_nativeFinishInit },
     { "nativeZygoteInit", "()V",
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index fbe3ece..e6c7c2b 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -1348,7 +1348,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gBitmapMethods[] = {
+static const JNINativeMethod gBitmapMethods[] = {
     {   "nativeCreate",             "([IIIIIIZ)Landroid/graphics/Bitmap;",
         (void*)Bitmap_creator },
     {   "nativeCopy",               "(JIZ)Landroid/graphics/Bitmap;",
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 20a54e5..28bc7fe 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -542,7 +542,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "nativeDecodeStream",
         "(Ljava/io/InputStream;[BLandroid/graphics/Rect;Landroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeStream
@@ -569,7 +569,7 @@
     },
 };
 
-static JNINativeMethod gOptionsMethods[] = {
+static const JNINativeMethod gOptionsMethods[] = {
     {   "requestCancel", "()V", (void*)nativeRequestCancel }
 };
 
diff --git a/core/jni/android/graphics/BitmapRegionDecoder.cpp b/core/jni/android/graphics/BitmapRegionDecoder.cpp
index 1bbbb089..2df3a46 100644
--- a/core/jni/android/graphics/BitmapRegionDecoder.cpp
+++ b/core/jni/android/graphics/BitmapRegionDecoder.cpp
@@ -261,7 +261,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gBitmapRegionDecoderMethods[] = {
+static const JNINativeMethod gBitmapRegionDecoderMethods[] = {
     {   "nativeDecodeRegion",
         "(JIIIILandroid/graphics/BitmapFactory$Options;)Landroid/graphics/Bitmap;",
         (void*)nativeDecodeRegion},
diff --git a/core/jni/android/graphics/Camera.cpp b/core/jni/android/graphics/Camera.cpp
index 036ece1..6fcf689 100644
--- a/core/jni/android/graphics/Camera.cpp
+++ b/core/jni/android/graphics/Camera.cpp
@@ -115,7 +115,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gCameraMethods[] = {
+static const JNINativeMethod gCameraMethods[] = {
     /* name, signature, funcPtr */
 
     { "nativeConstructor",   "()V",    (void*)Camera_constructor   },
diff --git a/core/jni/android/graphics/CanvasProperty.cpp b/core/jni/android/graphics/CanvasProperty.cpp
index deb4971..728bc1c 100644
--- a/core/jni/android/graphics/CanvasProperty.cpp
+++ b/core/jni/android/graphics/CanvasProperty.cpp
@@ -39,7 +39,7 @@
 // JNI Glue
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreateFloat", "(F)J", (void*) createFloat },
     { "nCreatePaint", "(J)J", (void*) createPaint },
 };
diff --git a/core/jni/android/graphics/ColorFilter.cpp b/core/jni/android/graphics/ColorFilter.cpp
index d03bcf0..83fd073 100644
--- a/core/jni/android/graphics/ColorFilter.cpp
+++ b/core/jni/android/graphics/ColorFilter.cpp
@@ -57,19 +57,19 @@
     }
 };
 
-static JNINativeMethod colorfilter_methods[] = {
+static const JNINativeMethod colorfilter_methods[] = {
     {"destroyFilter", "(J)V", (void*) SkColorFilterGlue::finalizer}
 };
 
-static JNINativeMethod porterduff_methods[] = {
+static const JNINativeMethod porterduff_methods[] = {
     { "native_CreatePorterDuffFilter", "(II)J", (void*) SkColorFilterGlue::CreatePorterDuffFilter   },
 };
 
-static JNINativeMethod lighting_methods[] = {
+static const JNINativeMethod lighting_methods[] = {
     { "native_CreateLightingFilter", "(II)J", (void*) SkColorFilterGlue::CreateLightingFilter   },
 };
 
-static JNINativeMethod colormatrix_methods[] = {
+static const JNINativeMethod colormatrix_methods[] = {
     { "nativeColorMatrixFilter", "([F)J", (void*) SkColorFilterGlue::CreateColorMatrixFilter   },
 };
 
diff --git a/core/jni/android/graphics/DrawFilter.cpp b/core/jni/android/graphics/DrawFilter.cpp
index 90ef6c0..c1dc0dd 100644
--- a/core/jni/android/graphics/DrawFilter.cpp
+++ b/core/jni/android/graphics/DrawFilter.cpp
@@ -97,11 +97,11 @@
     }
 };
 
-static JNINativeMethod drawfilter_methods[] = {
+static const JNINativeMethod drawfilter_methods[] = {
     {"nativeDestructor", "(J)V", (void*) SkDrawFilterGlue::finalizer}
 };
 
-static JNINativeMethod paintflags_methods[] = {
+static const JNINativeMethod paintflags_methods[] = {
     {"nativeConstructor","(II)J", (void*) SkDrawFilterGlue::CreatePaintFlagsDF}
 };
 
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index 38db76b..dac6d96 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -124,7 +124,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gFontFamilyMethods[] = {
+static const JNINativeMethod gFontFamilyMethods[] = {
     { "nCreateFamily",         "(Ljava/lang/String;I)J", (void*)FontFamily_create },
     { "nUnrefFamily",          "(J)V", (void*)FontFamily_unref },
     { "nAddFont",              "(JLjava/lang/String;)Z", (void*)FontFamily_addFont },
diff --git a/core/jni/android/graphics/Interpolator.cpp b/core/jni/android/graphics/Interpolator.cpp
index 3593d1a..fa28359 100644
--- a/core/jni/android/graphics/Interpolator.cpp
+++ b/core/jni/android/graphics/Interpolator.cpp
@@ -71,7 +71,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gInterpolatorMethods[] = {
+static const JNINativeMethod gInterpolatorMethods[] = {
     { "nativeConstructor",      "(II)J",        (void*)Interpolator_constructor     },
     { "nativeDestructor",       "(J)V",         (void*)Interpolator_destructor      },
     { "nativeReset",            "(JII)V",       (void*)Interpolator_reset           },
diff --git a/core/jni/android/graphics/MaskFilter.cpp b/core/jni/android/graphics/MaskFilter.cpp
index d658643..2b4a1ab 100644
--- a/core/jni/android/graphics/MaskFilter.cpp
+++ b/core/jni/android/graphics/MaskFilter.cpp
@@ -61,19 +61,19 @@
     }
 };
 
-static JNINativeMethod gMaskFilterMethods[] = {
+static const JNINativeMethod gMaskFilterMethods[] = {
     { "nativeDestructor",   "(J)V",     (void*)SkMaskFilterGlue::destructor      }
 };
 
-static JNINativeMethod gBlurMaskFilterMethods[] = {
+static const JNINativeMethod gBlurMaskFilterMethods[] = {
     { "nativeConstructor",  "(FI)J",    (void*)SkMaskFilterGlue::createBlur      }
 };
 
-static JNINativeMethod gEmbossMaskFilterMethods[] = {
+static const JNINativeMethod gEmbossMaskFilterMethods[] = {
     { "nativeConstructor",  "([FFFF)J", (void*)SkMaskFilterGlue::createEmboss    }
 };
 
-static JNINativeMethod gTableMaskFilterMethods[] = {
+static const JNINativeMethod gTableMaskFilterMethods[] = {
     { "nativeNewTable", "([B)J", (void*)SkMaskFilterGlue::createTable    },
     { "nativeNewClip",  "(II)J", (void*)SkMaskFilterGlue::createClipTable    },
     { "nativeNewGamma", "(F)J", (void*)SkMaskFilterGlue::createGammaTable    }
diff --git a/core/jni/android/graphics/Matrix.cpp b/core/jni/android/graphics/Matrix.cpp
index 101e2ba..b0f3bb4 100644
--- a/core/jni/android/graphics/Matrix.cpp
+++ b/core/jni/android/graphics/Matrix.cpp
@@ -302,7 +302,7 @@
     }
  };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) SkMatrixGlue::finalizer},
     {"native_create","(J)J", (void*) SkMatrixGlue::create},
 
diff --git a/core/jni/android/graphics/Movie.cpp b/core/jni/android/graphics/Movie.cpp
index d67ed10..498c590 100644
--- a/core/jni/android/graphics/Movie.cpp
+++ b/core/jni/android/graphics/Movie.cpp
@@ -135,7 +135,7 @@
 
 //////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "width",    "()I",  (void*)movie_width  },
     {   "height",   "()I",  (void*)movie_height  },
     {   "isOpaque", "()Z",  (void*)movie_isOpaque  },
diff --git a/core/jni/android/graphics/NinePatch.cpp b/core/jni/android/graphics/NinePatch.cpp
index 1c28262..3ccbb35 100644
--- a/core/jni/android/graphics/NinePatch.cpp
+++ b/core/jni/android/graphics/NinePatch.cpp
@@ -108,7 +108,7 @@
 
 /////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gNinePatchMethods[] = {
+static const JNINativeMethod gNinePatchMethods[] = {
     { "isNinePatchChunk", "([B)Z", (void*) SkNinePatchGlue::isNinePatchChunk },
     { "validateNinePatchChunk", "([B)J",
             (void*) SkNinePatchGlue::validateNinePatchChunk },
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 988d13a..223dae0 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -44,6 +44,7 @@
 #include "TypefaceImpl.h"
 
 #include <vector>
+#include <memory>
 
 // temporary for debugging
 #include <Caches.h>
@@ -569,137 +570,9 @@
         return descent - ascent + leading;
     }
 
-    static jfloat measureText_CIII(JNIEnv* env, jobject jpaint, jcharArray text, jint index, jint count,
-            jint bidiFlags) {
-        NPE_CHECK_RETURN_ZERO(env, jpaint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        size_t textLength = env->GetArrayLength(text);
-        if ((index | count) < 0 || (size_t)(index + count) > textLength) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-        if (count == 0) {
-            return 0;
-        }
-
-        Paint* paint = getNativePaint(env, jpaint);
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jfloat result = 0;
-
-        Layout layout;
-        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + index, 0, count,
-                count);
-        result = layout.getAdvance();
-        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray), JNI_ABORT);
-        return result;
-    }
-
-    static jfloat measureText_StringIII(JNIEnv* env, jobject jpaint, jstring text, jint start, jint end,
-            jint bidiFlags) {
-        NPE_CHECK_RETURN_ZERO(env, jpaint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        size_t textLength = env->GetStringLength(text);
-        int count = end - start;
-        if ((start | count) < 0 || (size_t)end > textLength) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-        if (count == 0) {
-            return 0;
-        }
-
-        const jchar* textArray = env->GetStringChars(text, NULL);
-        Paint* paint = getNativePaint(env, jpaint);
-        jfloat width = 0;
-
-        Layout layout;
-        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
-        // Only the substring is used for measurement, so no additional context is passed in. This
-        // behavior is consistent between char[] and String specializations.
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray + start, 0, count, count);
-        width = layout.getAdvance();
-
-        env->ReleaseStringChars(text, textArray);
-        return width;
-    }
-
-    static jfloat measureText_StringI(JNIEnv* env, jobject jpaint, jstring text, jint bidiFlags) {
-        NPE_CHECK_RETURN_ZERO(env, jpaint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        size_t textLength = env->GetStringLength(text);
-        if (textLength == 0) {
-            return 0;
-        }
-
-        const jchar* textArray = env->GetStringChars(text, NULL);
-        Paint* paint = getNativePaint(env, jpaint);
-        jfloat width = 0;
-
-        Layout layout;
-        TypefaceImpl* typeface = getNativeTypeface(env, jpaint);
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, textArray, 0, textLength, textLength);
-        width = layout.getAdvance();
-
-        env->ReleaseStringChars(text, textArray);
-        return width;
-    }
-
-    static int dotextwidths(JNIEnv* env, Paint* paint, TypefaceImpl* typeface, const jchar text[], int count,
-            jfloatArray widths, jint bidiFlags) {
-        NPE_CHECK_RETURN_ZERO(env, paint);
-        NPE_CHECK_RETURN_ZERO(env, text);
-
-        if (count < 0 || !widths) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-        if (count == 0) {
-            return 0;
-        }
-        size_t widthsLength = env->GetArrayLength(widths);
-        if ((size_t)count > widthsLength) {
-            doThrowAIOOBE(env);
-            return 0;
-        }
-
-        AutoJavaFloatArray autoWidths(env, widths, count);
-        jfloat* widthsArray = autoWidths.ptr();
-
-        Layout layout;
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, 0, count, count);
-        layout.getAdvances(widthsArray);
-
-        return count;
-    }
-
-    static jint getTextWidths___CIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jcharArray text,
-            jint index, jint count, jint bidiFlags, jfloatArray widths) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
-        const jchar* textArray = env->GetCharArrayElements(text, NULL);
-        count = dotextwidths(env, paint, typeface, textArray + index, count, widths, bidiFlags);
-        env->ReleaseCharArrayElements(text, const_cast<jchar*>(textArray),
-                                      JNI_ABORT);
-        return count;
-    }
-
-    static jint getTextWidths__StringIII_F(JNIEnv* env, jobject clazz, jlong paintHandle, jlong typefaceHandle, jstring text,
-            jint start, jint end, jint bidiFlags, jfloatArray widths) {
-        Paint* paint = reinterpret_cast<Paint*>(paintHandle);
-        TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
-        const jchar* textArray = env->GetStringChars(text, NULL);
-        int count = dotextwidths(env, paint, typeface, textArray + start, end - start, widths, bidiFlags);
-        env->ReleaseStringChars(text, textArray);
-        return count;
-    }
-
-    static jfloat doTextRunAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface, const jchar *text,
-                                    jint start, jint count, jint contextCount, jboolean isRtl,
-                                    jfloatArray advances, jint advancesIndex) {
+    static jfloat doTextAdvances(JNIEnv *env, Paint *paint, TypefaceImpl* typeface,
+            const jchar *text, jint start, jint count, jint contextCount, jint bidiFlags,
+            jfloatArray advances, jint advancesIndex) {
         NPE_CHECK_RETURN_ZERO(env, paint);
         NPE_CHECK_RETURN_ZERO(env, text);
 
@@ -712,50 +585,45 @@
         }
         if (advances) {
             size_t advancesLength = env->GetArrayLength(advances);
-            if ((size_t)count > advancesLength) {
+            if ((size_t)(count  + advancesIndex) > advancesLength) {
                 doThrowAIOOBE(env);
                 return 0;
             }
         }
-        jfloat* advancesArray = new jfloat[count];
-        jfloat totalAdvance = 0;
-
-        int bidiFlags = isRtl ? kBidi_Force_RTL : kBidi_Force_LTR;
 
         Layout layout;
-        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count, contextCount);
-        layout.getAdvances(advancesArray);
-        totalAdvance = layout.getAdvance();
-
+        MinikinUtils::doLayout(&layout, paint, bidiFlags, typeface, text, start, count,
+                contextCount);
         if (advances != NULL) {
-            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray);
+            std::unique_ptr<jfloat> advancesArray(new jfloat[count]);
+            layout.getAdvances(advancesArray.get());
+            env->SetFloatArrayRegion(advances, advancesIndex, count, advancesArray.get());
         }
-        delete [] advancesArray;
-        return totalAdvance;
+        return layout.getAdvance();
     }
 
-    static jfloat getTextRunAdvances___CIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+    static jfloat getTextAdvances___CIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
             jlong typefaceHandle,
             jcharArray text, jint index, jint count, jint contextIndex, jint contextCount,
-            jboolean isRtl, jfloatArray advances, jint advancesIndex) {
+            jint bidiFlags, jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         jchar* textArray = env->GetCharArrayElements(text, NULL);
-        jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextIndex,
-                index - contextIndex, count, contextCount, isRtl, advances, advancesIndex);
+        jfloat result = doTextAdvances(env, paint, typeface, textArray + contextIndex,
+                index - contextIndex, count, contextCount, bidiFlags, advances, advancesIndex);
         env->ReleaseCharArrayElements(text, textArray, JNI_ABORT);
         return result;
     }
 
-    static jfloat getTextRunAdvances__StringIIIIZ_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
+    static jfloat getTextAdvances__StringIIIII_FI(JNIEnv* env, jobject clazz, jlong paintHandle,
             jlong typefaceHandle,
-            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jboolean isRtl,
+            jstring text, jint start, jint end, jint contextStart, jint contextEnd, jint bidiFlags,
             jfloatArray advances, jint advancesIndex) {
         Paint* paint = reinterpret_cast<Paint*>(paintHandle);
         TypefaceImpl* typeface = reinterpret_cast<TypefaceImpl*>(typefaceHandle);
         const jchar* textArray = env->GetStringChars(text, NULL);
-        jfloat result = doTextRunAdvances(env, paint, typeface, textArray + contextStart,
-                start - contextStart, end - start, contextEnd - contextStart, isRtl,
+        jfloat result = doTextAdvances(env, paint, typeface, textArray + contextStart,
+                start - contextStart, end - start, contextEnd - contextStart, bidiFlags,
                 advances, advancesIndex);
         env->ReleaseStringChars(text, textArray);
         return result;
@@ -1095,7 +963,7 @@
 
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) PaintGlue::finalizer},
     {"native_init","()J", (void*) PaintGlue::init},
     {"native_initWithPaint","(J)J", (void*) PaintGlue::initWithPaint},
@@ -1160,18 +1028,13 @@
             (void*)PaintGlue::getFontMetrics},
     {"getFontMetricsInt", "!(Landroid/graphics/Paint$FontMetricsInt;)I",
             (void*)PaintGlue::getFontMetricsInt},
-    {"native_measureText","([CIII)F", (void*) PaintGlue::measureText_CIII},
-    {"native_measureText","(Ljava/lang/String;I)F", (void*) PaintGlue::measureText_StringI},
-    {"native_measureText","(Ljava/lang/String;III)F", (void*) PaintGlue::measureText_StringIII},
+
     {"native_breakText","(JJ[CIIFI[F)I", (void*) PaintGlue::breakTextC},
     {"native_breakText","(JJLjava/lang/String;ZFI[F)I", (void*) PaintGlue::breakTextS},
-    {"native_getTextWidths","(JJ[CIII[F)I", (void*) PaintGlue::getTextWidths___CIII_F},
-    {"native_getTextWidths","(JJLjava/lang/String;III[F)I",
-            (void*) PaintGlue::getTextWidths__StringIII_F},
-    {"native_getTextRunAdvances","(JJ[CIIIIZ[FI)F",
-            (void*) PaintGlue::getTextRunAdvances___CIIIIZ_FI},
-    {"native_getTextRunAdvances","(JJLjava/lang/String;IIIIZ[FI)F",
-            (void*) PaintGlue::getTextRunAdvances__StringIIIIZ_FI},
+    {"native_getTextAdvances","(JJ[CIIIII[FI)F",
+            (void*) PaintGlue::getTextAdvances___CIIIII_FI},
+    {"native_getTextAdvances","(JJLjava/lang/String;IIIII[FI)F",
+            (void*) PaintGlue::getTextAdvances__StringIIIII_FI},
 
     {"native_getTextRunCursor", "(J[CIIIII)I", (void*) PaintGlue::getTextRunCursor___C},
     {"native_getTextRunCursor", "(JLjava/lang/String;IIIII)I",
diff --git a/core/jni/android/graphics/Path.cpp b/core/jni/android/graphics/Path.cpp
index dbd7c89..2998c99 100644
--- a/core/jni/android/graphics/Path.cpp
+++ b/core/jni/android/graphics/Path.cpp
@@ -475,7 +475,7 @@
     }
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"finalizer", "(J)V", (void*) SkPathGlue::finalizer},
     {"init1","()J", (void*) SkPathGlue::init1},
     {"init2","(J)J", (void*) SkPathGlue::init2},
diff --git a/core/jni/android/graphics/PathEffect.cpp b/core/jni/android/graphics/PathEffect.cpp
index 265944e..b289b21 100644
--- a/core/jni/android/graphics/PathEffect.cpp
+++ b/core/jni/android/graphics/PathEffect.cpp
@@ -69,31 +69,31 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gPathEffectMethods[] = {
+static const JNINativeMethod gPathEffectMethods[] = {
     { "nativeDestructor", "(J)V", (void*)SkPathEffectGlue::destructor }
 };
 
-static JNINativeMethod gComposePathEffectMethods[] = {
+static const JNINativeMethod gComposePathEffectMethods[] = {
     { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Compose_constructor }
 };
 
-static JNINativeMethod gSumPathEffectMethods[] = {
+static const JNINativeMethod gSumPathEffectMethods[] = {
     { "nativeCreate", "(JJ)J", (void*)SkPathEffectGlue::Sum_constructor }
 };
 
-static JNINativeMethod gDashPathEffectMethods[] = {
+static const JNINativeMethod gDashPathEffectMethods[] = {
     { "nativeCreate", "([FF)J", (void*)SkPathEffectGlue::Dash_constructor }
 };
 
-static JNINativeMethod gPathDashPathEffectMethods[] = {
+static const JNINativeMethod gPathDashPathEffectMethods[] = {
     { "nativeCreate", "(JFFI)J", (void*)SkPathEffectGlue::OneD_constructor }
 };
 
-static JNINativeMethod gCornerPathEffectMethods[] = {
+static const JNINativeMethod gCornerPathEffectMethods[] = {
     { "nativeCreate", "(F)J", (void*)SkPathEffectGlue::Corner_constructor }
 };
 
-static JNINativeMethod gDiscretePathEffectMethods[] = {
+static const JNINativeMethod gDiscretePathEffectMethods[] = {
     { "nativeCreate", "(FF)J", (void*)SkPathEffectGlue::Discrete_constructor }
 };
 
diff --git a/core/jni/android/graphics/PathMeasure.cpp b/core/jni/android/graphics/PathMeasure.cpp
index fec5d9d..70e528d 100644
--- a/core/jni/android/graphics/PathMeasure.cpp
+++ b/core/jni/android/graphics/PathMeasure.cpp
@@ -143,7 +143,7 @@
     } 
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"native_create",       "(JZ)J",        (void*) SkPathMeasureGlue::create      },
     {"native_setPath",      "(JJZ)V",       (void*) SkPathMeasureGlue::setPath     },
     {"native_getLength",    "(J)F",         (void*) SkPathMeasureGlue::getLength   },
diff --git a/core/jni/android/graphics/PorterDuff.cpp b/core/jni/android/graphics/PorterDuff.cpp
index fed90a5..dfc3c9d 100644
--- a/core/jni/android/graphics/PorterDuff.cpp
+++ b/core/jni/android/graphics/PorterDuff.cpp
@@ -58,7 +58,7 @@
 
 };
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
     {"nativeCreateXfermode","(I)J", (void*) SkPorterDuffGlue::CreateXfermode},
 };
 
diff --git a/core/jni/android/graphics/Rasterizer.cpp b/core/jni/android/graphics/Rasterizer.cpp
index cfc23ac8..a106ecf 100644
--- a/core/jni/android/graphics/Rasterizer.cpp
+++ b/core/jni/android/graphics/Rasterizer.cpp
@@ -61,7 +61,7 @@
     }
 };
 
-static JNINativeMethod gRasterizerMethods[] = {
+static const JNINativeMethod gRasterizerMethods[] = {
     {"finalizer", "(J)V", (void*) SkRasterizerGlue::finalizer}
 };
 
@@ -85,7 +85,7 @@
     }
 };
 
-static JNINativeMethod gLayerRasterizerMethods[] = {
+static const JNINativeMethod gLayerRasterizerMethods[] = {
     { "nativeConstructor",  "()J",      (void*)SkLayerRasterizerGlue::create    },
     { "nativeAddLayer",     "(JJFF)V",  (void*)SkLayerRasterizerGlue::addLayer  }
 };
diff --git a/core/jni/android/graphics/Region.cpp b/core/jni/android/graphics/Region.cpp
index e99bdfc..bcd0b60 100644
--- a/core/jni/android/graphics/Region.cpp
+++ b/core/jni/android/graphics/Region.cpp
@@ -306,13 +306,13 @@
 
 ////////////////////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gRegionIterMethods[] = {
+static const JNINativeMethod gRegionIterMethods[] = {
     { "nativeConstructor",  "(J)J",                         (void*)RegionIter_constructor   },
     { "nativeDestructor",   "(J)V",                         (void*)RegionIter_destructor    },
     { "nativeNext",         "(JLandroid/graphics/Rect;)Z",  (void*)RegionIter_next          }
 };
 
-static JNINativeMethod gRegionMethods[] = {
+static const JNINativeMethod gRegionMethods[] = {
     // these are static methods
     { "nativeConstructor",      "()J",                              (void*)Region_constructor       },
     { "nativeDestructor",       "(J)V",                             (void*)Region_destructor        },
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 49c377e..799ed83 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -240,36 +240,36 @@
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gColorMethods[] = {
+static const JNINativeMethod gColorMethods[] = {
     { "nativeRGBToHSV",     "(III[F)V", (void*)Color_RGBToHSV   },
     { "nativeHSVToColor",   "(I[F)I",   (void*)Color_HSVToColor }
 };
 
-static JNINativeMethod gShaderMethods[] = {
+static const JNINativeMethod gShaderMethods[] = {
     { "nativeDestructor",        "(J)V",    (void*)Shader_destructor        },
     { "nativeSetLocalMatrix",    "(JJ)J",   (void*)Shader_setLocalMatrix    }
 };
 
-static JNINativeMethod gBitmapShaderMethods[] = {
+static const JNINativeMethod gBitmapShaderMethods[] = {
     { "nativeCreate",     "(Landroid/graphics/Bitmap;II)J",  (void*)BitmapShader_constructor },
 };
 
-static JNINativeMethod gLinearGradientMethods[] = {
+static const JNINativeMethod gLinearGradientMethods[] = {
     { "nativeCreate1",     "(FFFF[I[FI)J",  (void*)LinearGradient_create1     },
     { "nativeCreate2",     "(FFFFIII)J",    (void*)LinearGradient_create2     },
 };
 
-static JNINativeMethod gRadialGradientMethods[] = {
+static const JNINativeMethod gRadialGradientMethods[] = {
     { "nativeCreate1",     "(FFF[I[FI)J",  (void*)RadialGradient_create1     },
     { "nativeCreate2",     "(FFFIII)J",    (void*)RadialGradient_create2     },
 };
 
-static JNINativeMethod gSweepGradientMethods[] = {
+static const JNINativeMethod gSweepGradientMethods[] = {
     { "nativeCreate1",     "(FF[I[F)J",  (void*)SweepGradient_create1     },
     { "nativeCreate2",     "(FFII)J",    (void*)SweepGradient_create2     },
 };
 
-static JNINativeMethod gComposeShaderMethods[] = {
+static const JNINativeMethod gComposeShaderMethods[] = {
     { "nativeCreate1",      "(JJJ)J",   (void*)ComposeShader_create1     },
     { "nativeCreate2",      "(JJI)J",   (void*)ComposeShader_create2     },
 };
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 80de526..61dc6e4 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -359,7 +359,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gSurfaceTextureMethods[] = {
+static const JNINativeMethod gSurfaceTextureMethods[] = {
     {"nativeClassInit",            "()V",   (void*)SurfaceTexture_classInit },
     {"nativeInit",                 "(ZIZLjava/lang/ref/WeakReference;)V", (void*)SurfaceTexture_init },
     {"nativeFinalize",             "()V",   (void*)SurfaceTexture_finalize },
diff --git a/core/jni/android/graphics/Typeface.cpp b/core/jni/android/graphics/Typeface.cpp
index e0cbc9e..e97b768d 100644
--- a/core/jni/android/graphics/Typeface.cpp
+++ b/core/jni/android/graphics/Typeface.cpp
@@ -68,7 +68,7 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gTypefaceMethods[] = {
+static const JNINativeMethod gTypefaceMethods[] = {
     { "nativeCreateFromTypeface", "(JI)J", (void*)Typeface_createFromTypeface },
     { "nativeCreateWeightAlias",  "(JI)J", (void*)Typeface_createWeightAlias },
     { "nativeUnref",              "(J)V",  (void*)Typeface_unref },
diff --git a/core/jni/android/graphics/Xfermode.cpp b/core/jni/android/graphics/Xfermode.cpp
index 4a424ae..7441acc 100644
--- a/core/jni/android/graphics/Xfermode.cpp
+++ b/core/jni/android/graphics/Xfermode.cpp
@@ -47,15 +47,15 @@
 
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gXfermodeMethods[] = {
+static const JNINativeMethod gXfermodeMethods[] = {
     {"finalizer", "(J)V", (void*) SkXfermodeGlue::finalizer}
 };
 
-static JNINativeMethod gAvoidMethods[] = {
+static const JNINativeMethod gAvoidMethods[] = {
     {"nativeCreate", "(III)J", (void*) SkXfermodeGlue::avoid_create}
 };
 
-static JNINativeMethod gPixelXorMethods[] = {
+static const JNINativeMethod gPixelXorMethods[] = {
     {"nativeCreate", "(I)J", (void*) SkXfermodeGlue::pixelxor_create}
 };
 
diff --git a/core/jni/android/graphics/YuvToJpegEncoder.cpp b/core/jni/android/graphics/YuvToJpegEncoder.cpp
index 5eede2a..7d0c39c 100644
--- a/core/jni/android/graphics/YuvToJpegEncoder.cpp
+++ b/core/jni/android/graphics/YuvToJpegEncoder.cpp
@@ -243,7 +243,7 @@
 }
 ///////////////////////////////////////////////////////////////////////////////
 
-static JNINativeMethod gYuvImageMethods[] = {
+static const JNINativeMethod gYuvImageMethods[] = {
     {   "nativeCompressToJpeg",  "([BIII[I[IILjava/io/OutputStream;[B)Z",
         (void*)YuvImage_compressToJpeg }
 };
diff --git a/core/jni/android/graphics/pdf/PdfDocument.cpp b/core/jni/android/graphics/pdf/PdfDocument.cpp
index a91b15b..7a13fe4 100644
--- a/core/jni/android/graphics/pdf/PdfDocument.cpp
+++ b/core/jni/android/graphics/pdf/PdfDocument.cpp
@@ -150,7 +150,7 @@
     document->close();
 }
 
-static JNINativeMethod gPdfDocument_Methods[] = {
+static const JNINativeMethod gPdfDocument_Methods[] = {
     {"nativeCreateDocument", "()J", (void*) nativeCreateDocument},
     {"nativeStartPage", "(JIIIIII)J", (void*) nativeStartPage},
     {"nativeFinishPage", "(J)V", (void*) nativeFinishPage},
diff --git a/core/jni/android/graphics/pdf/PdfEditor.cpp b/core/jni/android/graphics/pdf/PdfEditor.cpp
index 52b69e0..0177635 100644
--- a/core/jni/android/graphics/pdf/PdfEditor.cpp
+++ b/core/jni/android/graphics/pdf/PdfEditor.cpp
@@ -343,7 +343,7 @@
     nativeSetPageBox(env, thiz, documentPtr, pageIndex, PAGE_BOX_CROP, mediaBox);
 }
 
-static JNINativeMethod gPdfEditor_Methods[] = {
+static const JNINativeMethod gPdfEditor_Methods[] = {
     {"nativeOpen", "(IJ)J", (void*) nativeOpen},
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
diff --git a/core/jni/android/graphics/pdf/PdfRenderer.cpp b/core/jni/android/graphics/pdf/PdfRenderer.cpp
index 006eef8..6ddfacf 100644
--- a/core/jni/android/graphics/pdf/PdfRenderer.cpp
+++ b/core/jni/android/graphics/pdf/PdfRenderer.cpp
@@ -283,7 +283,7 @@
     skBitmap.notifyPixelsChanged();
 }
 
-static JNINativeMethod gPdfRenderer_Methods[] = {
+static const JNINativeMethod gPdfRenderer_Methods[] = {
     {"nativeCreate", "(IJ)J", (void*) nativeCreate},
     {"nativeClose", "(J)V", (void*) nativeClose},
     {"nativeGetPageCount", "(J)I", (void*) nativeGetPageCount},
diff --git a/core/jni/android/opengl/util.cpp b/core/jni/android/opengl/util.cpp
index 40029bb..e045f5f 100644
--- a/core/jni/android/opengl/util.cpp
+++ b/core/jni/android/opengl/util.cpp
@@ -1087,18 +1087,18 @@
  * JNI registration
  */
 
-static JNINativeMethod gMatrixMethods[] = {
+static const JNINativeMethod gMatrixMethods[] = {
     { "multiplyMM", "([FI[FI[FI)V", (void*)util_multiplyMM },
     { "multiplyMV", "([FI[FI[FI)V", (void*)util_multiplyMV },
 };
 
-static JNINativeMethod gVisibilityMethods[] = {
+static const JNINativeMethod gVisibilityMethods[] = {
     { "computeBoundingSphere", "([FII[FI)V", (void*)util_computeBoundingSphere },
     { "frustumCullSpheres", "([FI[FII[III)I", (void*)util_frustumCullSpheres },
     { "visibilityTest", "([FI[FI[CII)I", (void*)util_visibilityTest },
 };
 
-static JNINativeMethod gUtilsMethods[] = {
+static const JNINativeMethod gUtilsMethods[] = {
     { "native_getInternalFormat", "(Landroid/graphics/Bitmap;)I", (void*) util_getInternalFormat },
     { "native_getType", "(Landroid/graphics/Bitmap;)I", (void*) util_getType },
     { "native_texImage2D", "(IIILandroid/graphics/Bitmap;II)I", (void*)util_texImage2D },
@@ -1106,7 +1106,7 @@
     { "setTracingLevel", "(I)V",                        (void*)setTracingLevel },
 };
 
-static JNINativeMethod gEtc1Methods[] = {
+static const JNINativeMethod gEtc1Methods[] = {
     { "encodeBlock", "(Ljava/nio/Buffer;ILjava/nio/Buffer;)V", (void*) etc1_encodeBlock },
     { "decodeBlock", "(Ljava/nio/Buffer;Ljava/nio/Buffer;)V", (void*) etc1_decodeBlock },
     { "getEncodedDataSize", "(II)I", (void*) etc1_getEncodedDataSize },
@@ -1120,11 +1120,11 @@
 
 typedef struct _ClassRegistrationInfo {
     const char* classPath;
-    JNINativeMethod* methods;
+    const JNINativeMethod* methods;
     size_t methodCount;
 } ClassRegistrationInfo;
 
-static ClassRegistrationInfo gClasses[] = {
+static const ClassRegistrationInfo gClasses[] = {
     {"android/opengl/Matrix", gMatrixMethods, NELEM(gMatrixMethods)},
     {"android/opengl/Visibility", gVisibilityMethods, NELEM(gVisibilityMethods)},
     {"android/opengl/GLUtils", gUtilsMethods, NELEM(gUtilsMethods)},
@@ -1136,7 +1136,7 @@
     nativeClassInitBuffer(env);
     int result = 0;
     for (int i = 0; i < NELEM(gClasses); i++) {
-        ClassRegistrationInfo* cri = &gClasses[i];
+        const ClassRegistrationInfo* cri = &gClasses[i];
         result = RegisterMethodsOrDie(env, cri->classPath, cri->methods, cri->methodCount);
     }
     return result;
diff --git a/core/jni/android_animation_PropertyValuesHolder.cpp b/core/jni/android_animation_PropertyValuesHolder.cpp
index d1177418..6065c24 100644
--- a/core/jni/android_animation_PropertyValuesHolder.cpp
+++ b/core/jni/android_animation_PropertyValuesHolder.cpp
@@ -139,7 +139,7 @@
     env->ReleaseIntArrayElements(arg, intValues, JNI_ABORT);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "nGetIntMethod", "(Ljava/lang/Class;Ljava/lang/String;)J",
             (void*)android_animation_PropertyValuesHolder_getIntMethod },
     {   "nGetFloatMethod", "(Ljava/lang/Class;Ljava/lang/String;)J",
diff --git a/core/jni/android_content_res_ObbScanner.cpp b/core/jni/android_content_res_ObbScanner.cpp
index ef17db6..36d78cf 100644
--- a/core/jni/android_content_res_ObbScanner.cpp
+++ b/core/jni/android_content_res_ObbScanner.cpp
@@ -76,7 +76,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "getObbInfo_native", "(Ljava/lang/String;Landroid/content/res/ObbInfo;)V",
             (void*) android_content_res_ObbScanner_getObbInfo },
diff --git a/core/jni/android_database_CursorWindow.cpp b/core/jni/android_database_CursorWindow.cpp
index 580ac02..bb09d00 100644
--- a/core/jni/android_database_CursorWindow.cpp
+++ b/core/jni/android_database_CursorWindow.cpp
@@ -477,7 +477,7 @@
     return true;
 }
 
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
     { "nativeCreate", "(Ljava/lang/String;I)J",
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index 7a3cdf6..bcc3bb0 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -786,7 +786,7 @@
 }
 
 
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZ)J",
diff --git a/core/jni/android_database_SQLiteDebug.cpp b/core/jni/android_database_SQLiteDebug.cpp
index 26e13cf..4e4c36c 100644
--- a/core/jni/android_database_SQLiteDebug.cpp
+++ b/core/jni/android_database_SQLiteDebug.cpp
@@ -58,7 +58,7 @@
  * JNI registration.
  */
 
-static JNINativeMethod gMethods[] =
+static const JNINativeMethod gMethods[] =
 {
     { "nativeGetPagerStats", "(Landroid/database/sqlite/SQLiteDebug$PagerStats;)V",
             (void*) nativeGetPagerStats },
diff --git a/core/jni/android_database_SQLiteGlobal.cpp b/core/jni/android_database_SQLiteGlobal.cpp
index 0a1c9f7..03e2387 100644
--- a/core/jni/android_database_SQLiteGlobal.cpp
+++ b/core/jni/android_database_SQLiteGlobal.cpp
@@ -75,7 +75,7 @@
     return sqlite3_release_memory(SOFT_HEAP_LIMIT);
 }
 
-static JNINativeMethod sMethods[] =
+static const JNINativeMethod sMethods[] =
 {
     /* name, signature, funcPtr */
     { "nativeReleaseMemory", "()I", (void*)nativeReleaseMemory },
diff --git a/core/jni/android_ddm_DdmHandleNativeHeap.cpp b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
index ae96936..3e7a04e 100644
--- a/core/jni/android_ddm_DdmHandleNativeHeap.cpp
+++ b/core/jni/android_ddm_DdmHandleNativeHeap.cpp
@@ -105,7 +105,7 @@
     return array;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "getLeakInfo", "()[B", (void*) DdmHandleNativeHeap_getLeakInfo },
 };
 
diff --git a/core/jni/android_graphics_Canvas.cpp b/core/jni/android_graphics_Canvas.cpp
index 5ddf2350..32a877a 100644
--- a/core/jni/android_graphics_Canvas.cpp
+++ b/core/jni/android_graphics_Canvas.cpp
@@ -746,7 +746,7 @@
 
 }; // namespace CanvasJNI
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"finalizer", "(J)V", (void*) CanvasJNI::finalizer},
     {"initRaster", "(Landroid/graphics/Bitmap;)J", (void*) CanvasJNI::initRaster},
     {"native_setBitmap", "(JLandroid/graphics/Bitmap;)V", (void*) CanvasJNI::setBitmap},
diff --git a/core/jni/android_graphics_Picture.cpp b/core/jni/android_graphics_Picture.cpp
index fd42ddb..03fcdef 100644
--- a/core/jni/android_graphics_Picture.cpp
+++ b/core/jni/android_graphics_Picture.cpp
@@ -91,7 +91,7 @@
     pict->endRecording();
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeGetWidth", "(J)I", (void*) android_graphics_Picture_getWidth},
     {"nativeGetHeight", "(J)I", (void*) android_graphics_Picture_getHeight},
     {"nativeConstructor", "(J)J", (void*) android_graphics_Picture_newPicture},
diff --git a/core/jni/android_hardware_Camera.cpp b/core/jni/android_hardware_Camera.cpp
index 4f44c262..414eba7 100644
--- a/core/jni/android_hardware_Camera.cpp
+++ b/core/jni/android_hardware_Camera.cpp
@@ -949,7 +949,7 @@
 
 //-------------------------------------------------
 
-static JNINativeMethod camMethods[] = {
+static const JNINativeMethod camMethods[] = {
   { "getNumberOfCameras",
     "()I",
     (void *)android_hardware_Camera_getNumberOfCameras },
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 7d0afdc..2e5cda0 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -343,7 +343,7 @@
 }
 //----------------------------------------------------------------------------
 
-static JNINativeMethod gSystemSensorManagerMethods[] = {
+static const JNINativeMethod gSystemSensorManagerMethods[] = {
     {"nativeClassInit",
             "()V",
             (void*)nativeClassInit },
@@ -360,7 +360,7 @@
             (void*)nativeIsDataInjectionEnabled},
 };
 
-static JNINativeMethod gBaseEventQueueMethods[] = {
+static const JNINativeMethod gBaseEventQueueMethods[] = {
     {"nativeInitBaseEventQueue",
              "(JLjava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;ILjava/lang/String;)J",
              (void*)nativeInitSensorEventQueue },
diff --git a/core/jni/android_hardware_SerialPort.cpp b/core/jni/android_hardware_SerialPort.cpp
index 2d2ff4d..393dc7b 100644
--- a/core/jni/android_hardware_SerialPort.cpp
+++ b/core/jni/android_hardware_SerialPort.cpp
@@ -243,7 +243,7 @@
     tcsendbreak(fd, 0);
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     {"native_open",             "(Ljava/io/FileDescriptor;I)V",
                                         (void *)android_hardware_SerialPort_open},
     {"native_close",            "()V",  (void *)android_hardware_SerialPort_close},
diff --git a/core/jni/android_hardware_SoundTrigger.cpp b/core/jni/android_hardware_SoundTrigger.cpp
index 1c4c9ec..048b3c7 100644
--- a/core/jni/android_hardware_SoundTrigger.cpp
+++ b/core/jni/android_hardware_SoundTrigger.cpp
@@ -768,14 +768,14 @@
     return status;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"listModules",
         "(Ljava/util/ArrayList;)I",
         (void *)android_hardware_SoundTrigger_listModules},
 };
 
 
-static JNINativeMethod gModuleMethods[] = {
+static const JNINativeMethod gModuleMethods[] = {
     {"native_setup",
         "(Ljava/lang/Object;)V",
         (void *)android_hardware_SoundTrigger_setup},
diff --git a/core/jni/android_hardware_UsbDevice.cpp b/core/jni/android_hardware_UsbDevice.cpp
index ef3b646..89d33e2 100644
--- a/core/jni/android_hardware_UsbDevice.cpp
+++ b/core/jni/android_hardware_UsbDevice.cpp
@@ -44,7 +44,7 @@
     return result;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     // static methods
     { "native_get_device_id", "(Ljava/lang/String;)I",
                                         (void*)android_hardware_UsbDevice_get_device_id },
diff --git a/core/jni/android_hardware_UsbDeviceConnection.cpp b/core/jni/android_hardware_UsbDeviceConnection.cpp
index e0cae6f..1ba9fc5 100644
--- a/core/jni/android_hardware_UsbDeviceConnection.cpp
+++ b/core/jni/android_hardware_UsbDeviceConnection.cpp
@@ -246,7 +246,7 @@
     return result;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     {"native_open",             "(Ljava/lang/String;Ljava/io/FileDescriptor;)Z",
                                         (void *)android_hardware_UsbDeviceConnection_open},
     {"native_close",            "()V",  (void *)android_hardware_UsbDeviceConnection_close},
diff --git a/core/jni/android_hardware_UsbRequest.cpp b/core/jni/android_hardware_UsbRequest.cpp
index ce99e15..399e7b1 100644
--- a/core/jni/android_hardware_UsbRequest.cpp
+++ b/core/jni/android_hardware_UsbRequest.cpp
@@ -190,7 +190,7 @@
     return (usb_request_cancel(request) == 0);
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     {"native_init",             "(Landroid/hardware/usb/UsbDeviceConnection;IIII)Z",
                                             (void *)android_hardware_UsbRequest_init},
     {"native_close",            "()V",      (void *)android_hardware_UsbRequest_close},
diff --git a/core/jni/android_hardware_camera2_CameraMetadata.cpp b/core/jni/android_hardware_camera2_CameraMetadata.cpp
index fb22689..7930027 100644
--- a/core/jni/android_hardware_camera2_CameraMetadata.cpp
+++ b/core/jni/android_hardware_camera2_CameraMetadata.cpp
@@ -529,7 +529,7 @@
 
 //-------------------------------------------------
 
-static JNINativeMethod gCameraMetadataMethods[] = {
+static const JNINativeMethod gCameraMetadataMethods[] = {
 // static methods
   { "nativeClassInit",
     "()V",
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 8b69bbd..738a62a 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -2280,7 +2280,7 @@
 
 } /*extern "C" */
 
-static JNINativeMethod gDngCreatorMethods[] = {
+static const JNINativeMethod gDngCreatorMethods[] = {
     {"nativeClassInit",        "()V", (void*) DngCreator_nativeClassInit},
     {"nativeInit", "(Landroid/hardware/camera2/impl/CameraMetadataNative;"
             "Landroid/hardware/camera2/impl/CameraMetadataNative;Ljava/lang/String;)V",
diff --git a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
index 63915ed..f1ea7ec 100644
--- a/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
+++ b/core/jni/android_hardware_camera2_legacy_LegacyCameraDevice.cpp
@@ -730,7 +730,7 @@
 
 } // extern "C"
 
-static JNINativeMethod gCameraDeviceMethods[] = {
+static const JNINativeMethod gCameraDeviceMethods[] = {
     { "nativeDetectSurfaceType",
     "(Landroid/view/Surface;)I",
     (void *)LegacyCameraDevice_nativeDetectSurfaceType },
diff --git a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
index 7257597..f042058 100644
--- a/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
+++ b/core/jni/android_hardware_camera2_legacy_PerfMeasurement.cpp
@@ -302,7 +302,7 @@
 
 } // extern "C"
 
-static JNINativeMethod gPerfMeasurementMethods[] = {
+static const JNINativeMethod gPerfMeasurementMethods[] = {
     { "nativeCreateContext",
       "(I)J",
       (jlong *)PerfMeasurement_nativeCreateContext },
diff --git a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
index 470c5ba..4b279f63 100644
--- a/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
+++ b/core/jni/android_hardware_location_ActivityRecognitionHardware.cpp
@@ -275,7 +275,7 @@
 }
 
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     // {"name", "signature", (void*) functionPointer },
     { "nativeClassInit", "()V", (void*) class_init },
     { "nativeInitialize", "()V", (void*) initialize },
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index 6c2bbd4..b977e37 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -682,7 +682,7 @@
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // name,               signature,  funcPtr
     {"native_start",         "(II)I",    (void *)android_media_AudioRecord_start},
     {"native_stop",          "()V",    (void *)android_media_AudioRecord_stop},
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 91b3278..6d3c7d7 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1616,7 +1616,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"setParameters",        "(Ljava/lang/String;)I", (void *)android_media_AudioSystem_setParameters},
     {"getParameters",        "(Ljava/lang/String;)Ljava/lang/String;", (void *)android_media_AudioSystem_getParameters},
     {"muteMicrophone",      "(Z)I",     (void *)android_media_AudioSystem_muteMicrophone},
@@ -1663,7 +1663,7 @@
 };
 
 
-static JNINativeMethod gEventHandlerMethods[] = {
+static const JNINativeMethod gEventHandlerMethods[] = {
     {"native_setup",
         "(Ljava/lang/Object;)V",
         (void *)android_media_AudioSystem_eventHandlerSetup},
diff --git a/core/jni/android_media_AudioTrack.cpp b/core/jni/android_media_AudioTrack.cpp
index 5faa150..7860b74 100644
--- a/core/jni/android_media_AudioTrack.cpp
+++ b/core/jni/android_media_AudioTrack.cpp
@@ -1052,7 +1052,7 @@
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // name,              signature,     funcPtr
     {"native_start",         "()V",      (void *)android_media_AudioTrack_start},
     {"native_stop",          "()V",      (void *)android_media_AudioTrack_stop},
diff --git a/core/jni/android_media_JetPlayer.cpp b/core/jni/android_media_JetPlayer.cpp
index d441f10..873c3f2 100644
--- a/core/jni/android_media_JetPlayer.cpp
+++ b/core/jni/android_media_JetPlayer.cpp
@@ -488,7 +488,7 @@
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // name,               signature,               funcPtr
     {"native_setup",       "(Ljava/lang/Object;II)Z", (void *)android_media_JetPlayer_setup},
     {"native_finalize",    "()V",                   (void *)android_media_JetPlayer_finalize},
diff --git a/core/jni/android_media_RemoteDisplay.cpp b/core/jni/android_media_RemoteDisplay.cpp
index 9bc223b..bd1a6ec 100644
--- a/core/jni/android_media_RemoteDisplay.cpp
+++ b/core/jni/android_media_RemoteDisplay.cpp
@@ -177,7 +177,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeListen", "(Ljava/lang/String;Ljava/lang/String;)J",
             (void*)nativeListen },
     {"nativeDispose", "(J)V",
diff --git a/core/jni/android_media_ToneGenerator.cpp b/core/jni/android_media_ToneGenerator.cpp
index 243f040..aec6263 100644
--- a/core/jni/android_media_ToneGenerator.cpp
+++ b/core/jni/android_media_ToneGenerator.cpp
@@ -123,7 +123,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "startTone", "(II)Z", (void *)android_media_ToneGenerator_startTone },
     { "stopTone", "()V", (void *)android_media_ToneGenerator_stopTone },
     { "getAudioSessionId", "()I", (void *)android_media_ToneGenerator_getAudioSessionId},
diff --git a/core/jni/android_net_LocalSocketImpl.cpp b/core/jni/android_net_LocalSocketImpl.cpp
index c137b17..d6d4310 100644
--- a/core/jni/android_net_LocalSocketImpl.cpp
+++ b/core/jni/android_net_LocalSocketImpl.cpp
@@ -495,7 +495,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
      /* name, signature, funcPtr */
     {"connectLocal", "(Ljava/io/FileDescriptor;Ljava/lang/String;I)V",
                                                 (void*)socket_connect_local},
diff --git a/core/jni/android_net_NetUtils.cpp b/core/jni/android_net_NetUtils.cpp
index fada7ac2..ba0876d 100644
--- a/core/jni/android_net_NetUtils.cpp
+++ b/core/jni/android_net_NetUtils.cpp
@@ -302,7 +302,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gNetworkUtilMethods[] = {
+static const JNINativeMethod gNetworkUtilMethods[] = {
     /* name, signature, funcPtr */
     { "resetConnections", "(Ljava/lang/String;I)I",  (void *)android_net_utils_resetConnections },
     { "startDhcp", "(Ljava/lang/String;)Z",  (void *)android_net_utils_startDhcp },
diff --git a/core/jni/android_net_TrafficStats.cpp b/core/jni/android_net_TrafficStats.cpp
index 7354417..7b7d0cf 100644
--- a/core/jni/android_net_TrafficStats.cpp
+++ b/core/jni/android_net_TrafficStats.cpp
@@ -185,7 +185,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeGetTotalStat", "(I)J", (void*) getTotalStat},
     {"nativeGetIfaceStat", "(Ljava/lang/String;I)J", (void*) getIfaceStat},
     {"nativeGetUidStat", "(II)J", (void*) getUidStat},
diff --git a/core/jni/android_opengl_EGL14.cpp b/core/jni/android_opengl_EGL14.cpp
index 9f5b3bc..568473c 100644
--- a/core/jni/android_opengl_EGL14.cpp
+++ b/core/jni/android_opengl_EGL14.cpp
@@ -1231,7 +1231,7 @@
 
 static const char *classPathName = "android/opengl/EGL14";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"eglGetError", "()I", (void *) android_eglGetError },
 {"eglGetDisplay", "(I)Landroid/opengl/EGLDisplay;", (void *) android_eglGetDisplayInt },
diff --git a/core/jni/android_opengl_EGLExt.cpp b/core/jni/android_opengl_EGLExt.cpp
index 60a3bf6..62ccad4 100644
--- a/core/jni/android_opengl_EGLExt.cpp
+++ b/core/jni/android_opengl_EGLExt.cpp
@@ -149,7 +149,7 @@
 
 static const char *classPathName = "android/opengl/EGLExt";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"eglPresentationTimeANDROID", "(Landroid/opengl/EGLDisplay;Landroid/opengl/EGLSurface;J)Z", (void *) android_eglPresentationTimeANDROID },
 };
diff --git a/core/jni/android_opengl_GLES10.cpp b/core/jni/android_opengl_GLES10.cpp
index dac98de..f4135c2 100644
--- a/core/jni/android_opengl_GLES10.cpp
+++ b/core/jni/android_opengl_GLES10.cpp
@@ -3184,7 +3184,7 @@
 
 static const char *classPathName = "android/opengl/GLES10";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
 {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
diff --git a/core/jni/android_opengl_GLES10Ext.cpp b/core/jni/android_opengl_GLES10Ext.cpp
index 95be11b..4dc4233 100644
--- a/core/jni/android_opengl_GLES10Ext.cpp
+++ b/core/jni/android_opengl_GLES10Ext.cpp
@@ -582,7 +582,7 @@
 
 static const char *classPathName = "android/opengl/GLES10Ext";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glQueryMatrixxOES", "([II[II)I", (void *) android_glQueryMatrixxOES___3II_3II },
 {"glQueryMatrixxOES", "(Ljava/nio/IntBuffer;Ljava/nio/IntBuffer;)I", (void *) android_glQueryMatrixxOES__Ljava_nio_IntBuffer_2Ljava_nio_IntBuffer_2 },
diff --git a/core/jni/android_opengl_GLES11.cpp b/core/jni/android_opengl_GLES11.cpp
index 6970a3c..2625e03 100644
--- a/core/jni/android_opengl_GLES11.cpp
+++ b/core/jni/android_opengl_GLES11.cpp
@@ -3065,7 +3065,7 @@
 
 static const char *classPathName = "android/opengl/GLES11";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glBindBuffer", "(II)V", (void *) android_glBindBuffer__II },
 {"glBufferData", "(IILjava/nio/Buffer;I)V", (void *) android_glBufferData__IILjava_nio_Buffer_2I },
diff --git a/core/jni/android_opengl_GLES11Ext.cpp b/core/jni/android_opengl_GLES11Ext.cpp
index 6422ff2..fb85cb0 100644
--- a/core/jni/android_opengl_GLES11Ext.cpp
+++ b/core/jni/android_opengl_GLES11Ext.cpp
@@ -3573,7 +3573,7 @@
 
 static const char *classPathName = "android/opengl/GLES11Ext";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glBlendEquationSeparateOES", "(II)V", (void *) android_glBlendEquationSeparateOES__II },
 {"glBlendFuncSeparateOES", "(IIII)V", (void *) android_glBlendFuncSeparateOES__IIII },
diff --git a/core/jni/android_opengl_GLES20.cpp b/core/jni/android_opengl_GLES20.cpp
index f9a0dfe..b9f61a9 100644
--- a/core/jni/android_opengl_GLES20.cpp
+++ b/core/jni/android_opengl_GLES20.cpp
@@ -6152,7 +6152,7 @@
 
 static const char *classPathName = "android/opengl/GLES20";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
 {"glAttachShader", "(II)V", (void *) android_glAttachShader__II },
diff --git a/core/jni/android_opengl_GLES30.cpp b/core/jni/android_opengl_GLES30.cpp
index 1d92cd4..8eb5044 100644
--- a/core/jni/android_opengl_GLES30.cpp
+++ b/core/jni/android_opengl_GLES30.cpp
@@ -5167,7 +5167,7 @@
 
 static const char *classPathName = "android/opengl/GLES30";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glReadBuffer", "(I)V", (void *) android_glReadBuffer__I },
 {"glDrawRangeElements", "(IIIIILjava/nio/Buffer;)V", (void *) android_glDrawRangeElements__IIIIILjava_nio_Buffer_2 },
diff --git a/core/jni/android_opengl_GLES31.cpp b/core/jni/android_opengl_GLES31.cpp
index 92ecbe0..e427388 100644
--- a/core/jni/android_opengl_GLES31.cpp
+++ b/core/jni/android_opengl_GLES31.cpp
@@ -3175,7 +3175,7 @@
 
 static const char *classPathName = "android/opengl/GLES31";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glDispatchCompute", "(III)V", (void *) android_glDispatchCompute__III },
 {"glDispatchComputeIndirect", "(J)V", (void *) android_glDispatchComputeIndirect },
diff --git a/core/jni/android_opengl_GLES31Ext.cpp b/core/jni/android_opengl_GLES31Ext.cpp
index 2856308..180c693 100644
--- a/core/jni/android_opengl_GLES31Ext.cpp
+++ b/core/jni/android_opengl_GLES31Ext.cpp
@@ -1443,7 +1443,7 @@
 
 static const char *classPathName = "android/opengl/GLES31Ext";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glBlendBarrierKHR", "()V", (void *) android_glBlendBarrierKHR__ },
 {"glDebugMessageControlKHR", "(IIII[IIZ)V", (void *) android_glDebugMessageControlKHR__IIII_3IIZ },
diff --git a/core/jni/android_os_Debug.cpp b/core/jni/android_os_Debug.cpp
index b969477..097bbac 100644
--- a/core/jni/android_os_Debug.cpp
+++ b/core/jni/android_os_Debug.cpp
@@ -973,7 +973,7 @@
  * JNI registration.
  */
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "getNativeHeapSize",      "()J",
             (void*) android_os_Debug_getNativeHeapSize },
     { "getNativeHeapAllocatedSize", "()J",
diff --git a/core/jni/android_os_MessageQueue.cpp b/core/jni/android_os_MessageQueue.cpp
index d2db3c9..e57a719 100644
--- a/core/jni/android_os_MessageQueue.cpp
+++ b/core/jni/android_os_MessageQueue.cpp
@@ -209,7 +209,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMessageQueueMethods[] = {
+static const JNINativeMethod gMessageQueueMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit", "()J", (void*)android_os_MessageQueue_nativeInit },
     { "nativeDestroy", "(J)V", (void*)android_os_MessageQueue_nativeDestroy },
diff --git a/core/jni/android_os_SELinux.cpp b/core/jni/android_os_SELinux.cpp
index 762b88f..8ba77ae 100644
--- a/core/jni/android_os_SELinux.cpp
+++ b/core/jni/android_os_SELinux.cpp
@@ -320,7 +320,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     /* name,                     signature,                    funcPtr */
     { "checkSELinuxAccess"       , "(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Z" , (void*)checkSELinuxAccess },
     { "getContext"               , "()Ljava/lang/String;"                         , (void*)getCon           },
diff --git a/core/jni/android_os_SystemClock.cpp b/core/jni/android_os_SystemClock.cpp
index dfe024e..d98407d 100644
--- a/core/jni/android_os_SystemClock.cpp
+++ b/core/jni/android_os_SystemClock.cpp
@@ -104,7 +104,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "uptimeMillis",      "()J",
             (void*) android_os_SystemClock_uptimeMillis },
diff --git a/core/jni/android_os_SystemProperties.cpp b/core/jni/android_os_SystemProperties.cpp
index 554d304..5dace6b 100644
--- a/core/jni/android_os_SystemProperties.cpp
+++ b/core/jni/android_os_SystemProperties.cpp
@@ -220,7 +220,7 @@
     }
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "native_get", "(Ljava/lang/String;)Ljava/lang/String;",
       (void*) SystemProperties_getS },
     { "native_get", "(Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;",
diff --git a/core/jni/android_os_Trace.cpp b/core/jni/android_os_Trace.cpp
index 3fd3b3c..30fc47b 100644
--- a/core/jni/android_os_Trace.cpp
+++ b/core/jni/android_os_Trace.cpp
@@ -105,7 +105,7 @@
     atrace_set_tracing_enabled(enabled);
 }
 
-static JNINativeMethod gTraceMethods[] = {
+static const JNINativeMethod gTraceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeGetEnabledTags",
             "()J",
diff --git a/core/jni/android_os_UEventObserver.cpp b/core/jni/android_os_UEventObserver.cpp
index eb36f85..30d40a2 100644
--- a/core/jni/android_os_UEventObserver.cpp
+++ b/core/jni/android_os_UEventObserver.cpp
@@ -103,7 +103,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nativeSetup", "()V",
             (void *)nativeSetup },
     { "nativeWaitForNextEvent", "()Ljava/lang/String;",
diff --git a/core/jni/android_server_NetworkManagementSocketTagger.cpp b/core/jni/android_server_NetworkManagementSocketTagger.cpp
index ca21fd7..818bf53 100644
--- a/core/jni/android_server_NetworkManagementSocketTagger.cpp
+++ b/core/jni/android_server_NetworkManagementSocketTagger.cpp
@@ -83,7 +83,7 @@
   return (jint)res;
 }
 
-static JNINativeMethod gQTagUidMethods[] = {
+static const JNINativeMethod gQTagUidMethods[] = {
   { "native_tagSocketFd", "(Ljava/io/FileDescriptor;II)I", (void*)QTagUid_tagSocketFd},
   { "native_untagSocketFd", "(Ljava/io/FileDescriptor;)I", (void*)QTagUid_untagSocketFd},
   { "native_setCounterSet", "(II)I", (void*)QTagUid_setCounterSet},
diff --git a/core/jni/android_text_AndroidBidi.cpp b/core/jni/android_text_AndroidBidi.cpp
index 3285429..2a3f036 100644
--- a/core/jni/android_text_AndroidBidi.cpp
+++ b/core/jni/android_text_AndroidBidi.cpp
@@ -56,7 +56,7 @@
     return result;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
         { "runBidi", "(I[C[BIZ)I", (void*) runBidi }
 };
 
diff --git a/core/jni/android_text_AndroidCharacter.cpp b/core/jni/android_text_AndroidCharacter.cpp
index 9258248..474a74e 100644
--- a/core/jni/android_text_AndroidCharacter.cpp
+++ b/core/jni/android_text_AndroidCharacter.cpp
@@ -178,7 +178,7 @@
     return u_charMirror(c);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
 	{ "getDirectionalities", "([C[BI)V",
         (void*) getDirectionalities },
 	{ "getEastAsianWidth", "(C)I",
diff --git a/core/jni/android_text_StaticLayout.cpp b/core/jni/android_text_StaticLayout.cpp
index a94ea8b..83f76ea 100644
--- a/core/jni/android_text_StaticLayout.cpp
+++ b/core/jni/android_text_StaticLayout.cpp
@@ -180,7 +180,7 @@
     env->SetFloatArrayRegion(widths, 0, b->size(), b->charWidths());
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     // TODO performance: many of these are candidates for fast jni, awaiting guidance
     {"nNewBuilder", "()J", (void*) nNewBuilder},
     {"nFreeBuilder", "(J)V", (void*) nFreeBuilder},
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 7ca0654..614e82f 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -2112,7 +2112,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gAssetManagerMethods[] = {
+static const JNINativeMethod gAssetManagerMethods[] = {
     /* name, signature, funcPtr */
 
     // Basic asset stuff.
diff --git a/core/jni/android_util_EventLog.cpp b/core/jni/android_util_EventLog.cpp
index 05bc125..4f8a2cb 100644
--- a/core/jni/android_util_EventLog.cpp
+++ b/core/jni/android_util_EventLog.cpp
@@ -249,7 +249,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gRegisterMethods[] = {
+static const JNINativeMethod gRegisterMethods[] = {
     /* name, signature, funcPtr */
     { "writeEvent", "(II)I", (void*) android_util_EventLog_writeEvent_Integer },
     { "writeEvent", "(IJ)I", (void*) android_util_EventLog_writeEvent_Long },
diff --git a/core/jni/android_util_FileObserver.cpp b/core/jni/android_util_FileObserver.cpp
index 067d298..2b93b6d 100644
--- a/core/jni/android_util_FileObserver.cpp
+++ b/core/jni/android_util_FileObserver.cpp
@@ -127,7 +127,7 @@
 #endif
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     { "init", "()I", (void*)android_os_fileobserver_init },
     { "observe", "(I)V", (void*)android_os_fileobserver_observe },
diff --git a/core/jni/android_util_Log.cpp b/core/jni/android_util_Log.cpp
index 2b1067b..2d23cda 100644
--- a/core/jni/android_util_Log.cpp
+++ b/core/jni/android_util_Log.cpp
@@ -111,7 +111,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "isLoggable",      "(Ljava/lang/String;I)Z", (void*) android_util_Log_isLoggable },
     { "println_native",  "(IILjava/lang/String;Ljava/lang/String;)I", (void*) android_util_Log_println_native },
diff --git a/core/jni/android_util_StringBlock.cpp b/core/jni/android_util_StringBlock.cpp
index f83eaec..b396afe 100644
--- a/core/jni/android_util_StringBlock.cpp
+++ b/core/jni/android_util_StringBlock.cpp
@@ -155,7 +155,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gStringBlockMethods[] = {
+static const JNINativeMethod gStringBlockMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate",      "([BII)J",
             (void*) android_content_StringBlock_nativeCreate },
diff --git a/core/jni/android_util_XmlBlock.cpp b/core/jni/android_util_XmlBlock.cpp
index 375710e..7ae51c8 100644
--- a/core/jni/android_util_XmlBlock.cpp
+++ b/core/jni/android_util_XmlBlock.cpp
@@ -364,7 +364,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gXmlBlockMethods[] = {
+static const JNINativeMethod gXmlBlockMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate",               "([BII)J",
             (void*) android_content_XmlBlock_nativeCreate },
diff --git a/core/jni/android_view_DisplayEventReceiver.cpp b/core/jni/android_view_DisplayEventReceiver.cpp
index 0e2ec6b..437bd19 100644
--- a/core/jni/android_view_DisplayEventReceiver.cpp
+++ b/core/jni/android_view_DisplayEventReceiver.cpp
@@ -259,7 +259,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_GraphicBuffer.cpp b/core/jni/android_view_GraphicBuffer.cpp
index 17d2a5e..7682dd6 100644
--- a/core/jni/android_view_GraphicBuffer.cpp
+++ b/core/jni/android_view_GraphicBuffer.cpp
@@ -268,7 +268,7 @@
 
 const char* const kClassPathName = "android/view/GraphicBuffer";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreateGraphicBuffer",  "(IIII)J", (void*) android_view_GraphiceBuffer_create },
     { "nDestroyGraphicBuffer", "(J)V",    (void*) android_view_GraphiceBuffer_destroy },
 
diff --git a/core/jni/android_view_HardwareLayer.cpp b/core/jni/android_view_HardwareLayer.cpp
index 36ba892..3a0ddc9 100644
--- a/core/jni/android_view_HardwareLayer.cpp
+++ b/core/jni/android_view_HardwareLayer.cpp
@@ -85,7 +85,7 @@
 
 const char* const kClassPathName = "android/view/HardwareLayer";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nPrepare",                "(JIIZ)Z",    (void*) android_view_HardwareLayer_prepare },
     { "nSetLayerPaint",          "(JJ)V",      (void*) android_view_HardwareLayer_setLayerPaint },
     { "nSetTransform",           "(JJ)V",      (void*) android_view_HardwareLayer_setTransform },
diff --git a/core/jni/android_view_InputChannel.cpp b/core/jni/android_view_InputChannel.cpp
index 4b42ab5..092ac27 100644
--- a/core/jni/android_view_InputChannel.cpp
+++ b/core/jni/android_view_InputChannel.cpp
@@ -259,7 +259,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gInputChannelMethods[] = {
+static const JNINativeMethod gInputChannelMethods[] = {
     /* name, signature, funcPtr */
     { "nativeOpenInputChannelPair", "(Ljava/lang/String;)[Landroid/view/InputChannel;",
             (void*)android_view_InputChannel_nativeOpenInputChannelPair },
diff --git a/core/jni/android_view_InputEventReceiver.cpp b/core/jni/android_view_InputEventReceiver.cpp
index 43b8471..8293cd8 100644
--- a/core/jni/android_view_InputEventReceiver.cpp
+++ b/core/jni/android_view_InputEventReceiver.cpp
@@ -395,7 +395,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_InputEventSender.cpp b/core/jni/android_view_InputEventSender.cpp
index d61dee7..3bd6917 100644
--- a/core/jni/android_view_InputEventSender.cpp
+++ b/core/jni/android_view_InputEventSender.cpp
@@ -289,7 +289,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Ljava/lang/ref/WeakReference;Landroid/view/InputChannel;Landroid/os/MessageQueue;)J",
diff --git a/core/jni/android_view_KeyCharacterMap.cpp b/core/jni/android_view_KeyCharacterMap.cpp
index 7653f58..e5519a7 100644
--- a/core/jni/android_view_KeyCharacterMap.cpp
+++ b/core/jni/android_view_KeyCharacterMap.cpp
@@ -203,7 +203,7 @@
  * JNI registration.
  */
 
-static JNINativeMethod g_methods[] = {
+static const JNINativeMethod g_methods[] = {
     /* name, signature, funcPtr */
     { "nativeReadFromParcel", "(Landroid/os/Parcel;)J",
             (void*)nativeReadFromParcel },
diff --git a/core/jni/android_view_MotionEvent.cpp b/core/jni/android_view_MotionEvent.cpp
index 98c17c0..81d46c3 100644
--- a/core/jni/android_view_MotionEvent.cpp
+++ b/core/jni/android_view_MotionEvent.cpp
@@ -752,7 +752,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMotionEventMethods[] = {
+static const JNINativeMethod gMotionEventMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInitialize",
             "(JIIIIIIIFFFFJJI[Landroid/view/MotionEvent$PointerProperties;"
diff --git a/core/jni/android_view_RenderNode.cpp b/core/jni/android_view_RenderNode.cpp
index a3b3700..388d365 100644
--- a/core/jni/android_view_RenderNode.cpp
+++ b/core/jni/android_view_RenderNode.cpp
@@ -467,7 +467,7 @@
 
 const char* const kClassPathName = "android/view/RenderNode";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreate",               "(Ljava/lang/String;)J",    (void*) android_view_RenderNode_create },
     { "nDestroyRenderNode",   "(J)V",   (void*) android_view_RenderNode_destroyRenderNode },
     { "nSetDisplayListData",   "(JJ)V", (void*) android_view_RenderNode_setDisplayListData },
diff --git a/core/jni/android_view_RenderNodeAnimator.cpp b/core/jni/android_view_RenderNodeAnimator.cpp
index 4177ee2..0926e9b 100644
--- a/core/jni/android_view_RenderNodeAnimator.cpp
+++ b/core/jni/android_view_RenderNodeAnimator.cpp
@@ -193,7 +193,7 @@
 
 const char* const kClassPathName = "android/view/RenderNodeAnimator";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nCreateAnimator", "(IF)J", (void*) createAnimator },
     { "nCreateCanvasPropertyFloatAnimator", "(JF)J", (void*) createCanvasPropertyFloatAnimator },
     { "nCreateCanvasPropertyPaintAnimator", "(JIF)J", (void*) createCanvasPropertyPaintAnimator },
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 4a311d31..24055e7 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -514,7 +514,7 @@
 
 namespace hwui = android::uirenderer;
 
-static JNINativeMethod gSurfaceMethods[] = {
+static const JNINativeMethod gSurfaceMethods[] = {
     {"nativeCreateFromSurfaceTexture", "(Landroid/graphics/SurfaceTexture;)J",
             (void*)nativeCreateFromSurfaceTexture },
     {"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceControl.cpp b/core/jni/android_view_SurfaceControl.cpp
index d1acb59..65ebb663 100644
--- a/core/jni/android_view_SurfaceControl.cpp
+++ b/core/jni/android_view_SurfaceControl.cpp
@@ -572,7 +572,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod sSurfaceControlMethods[] = {
+static const JNINativeMethod sSurfaceControlMethods[] = {
     {"nativeCreate", "(Landroid/view/SurfaceSession;Ljava/lang/String;IIII)J",
             (void*)nativeCreate },
     {"nativeRelease", "(J)V",
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 609c565..dad6958 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -56,7 +56,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "nativeCreate", "()J",
             (void*)nativeCreate },
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index beb83b1..b736a17c 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -197,7 +197,7 @@
 
 const char* const kClassPathName = "android/view/TextureView";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {   "nCreateNativeWindow", "(Landroid/graphics/SurfaceTexture;)V",
             (void*) android_view_TextureView_createNativeWindow },
     {   "nDestroyNativeWindow", "()V",
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 9a2703b..c79f833 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -484,7 +484,7 @@
 
 const char* const kClassPathName = "android/view/ThreadedRenderer";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nSetAtlas", "(JLandroid/view/GraphicBuffer;[J)V",   (void*) android_view_ThreadedRenderer_setAtlas },
     { "nSetProcessStatsBuffer", "(JI)V", (void*) android_view_ThreadedRenderer_setProcessStatsBuffer },
     { "nCreateRootRenderNode", "()J", (void*) android_view_ThreadedRenderer_createRootRenderNode },
diff --git a/core/jni/android_view_VelocityTracker.cpp b/core/jni/android_view_VelocityTracker.cpp
index ddd5fc8..04ec705 100644
--- a/core/jni/android_view_VelocityTracker.cpp
+++ b/core/jni/android_view_VelocityTracker.cpp
@@ -215,7 +215,7 @@
 
 // --- JNI Registration ---
 
-static JNINativeMethod gVelocityTrackerMethods[] = {
+static const JNINativeMethod gVelocityTrackerMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInitialize",
             "(Ljava/lang/String;)J",
diff --git a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
index daa6f82..364ac44 100644
--- a/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
+++ b/core/jni/com_android_internal_content_NativeLibraryHelper.cpp
@@ -561,7 +561,7 @@
     delete reinterpret_cast<ZipFileRO*>(apkHandle);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"nativeOpenApk",
             "(Ljava/lang/String;)J",
             (void *)com_android_internal_content_NativeLibraryHelper_openApk},
diff --git a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
index 6c0b756..70134ab 100644
--- a/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
+++ b/core/jni/com_android_internal_net_NetworkStatsFactory.cpp
@@ -284,7 +284,7 @@
     return 0;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
         { "nativeReadNetworkStatsDetail",
                 "(Landroid/net/NetworkStats;Ljava/lang/String;I[Ljava/lang/String;I)I",
                 (void*) readNetworkStatsDetail }
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index aef70be..3f1be456 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -647,7 +647,7 @@
   return pid;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nativeForkAndSpecialize",
       "(II[II[[IILjava/lang/String;Ljava/lang/String;[ILjava/lang/String;Ljava/lang/String;)I",
       (void *) com_android_internal_os_Zygote_nativeForkAndSpecialize },
diff --git a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
index 7a18c2d..d20bae2 100644
--- a/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
+++ b/core/jni/com_android_internal_util_VirtualRefBasePtr.cpp
@@ -36,7 +36,7 @@
 
 const char* const kClassPathName = "com/android/internal/util/VirtualRefBasePtr";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nIncStrong", "(J)V", (void*) incStrong },
     { "nDecStrong", "(J)V", (void*) decStrong },
 };
diff --git a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
index 2c65d62..6781e13 100644
--- a/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
+++ b/core/jni/com_android_internal_view_animation_NativeInterpolatorFactoryHelper.cpp
@@ -78,7 +78,7 @@
 
 const char* const kClassPathName = "com/android/internal/view/animation/NativeInterpolatorFactoryHelper";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "createAccelerateDecelerateInterpolator", "()J", (void*) createAccelerateDecelerateInterpolator },
     { "createAccelerateInterpolator", "(F)J", (void*) createAccelerateInterpolator },
     { "createAnticipateInterpolator", "(F)J", (void*) createAnticipateInterpolator },
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index baeb7dd..3d63b01 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -532,7 +532,7 @@
 #define OBJECT  "Ljava/lang/Object;"
 #define STRING  "Ljava/lang/String;"
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit","()V", (void*)nativeClassInit },
 {"eglWaitGL",       "()Z", (void*)jni_eglWaitGL },
 {"eglInitialize",   "(" DISPLAY "[I)Z", (void*)jni_eglInitialize },
diff --git a/core/jni/com_google_android_gles_jni_GLImpl.cpp b/core/jni/com_google_android_gles_jni_GLImpl.cpp
index f15f957..ad7d744 100644
--- a/core/jni/com_google_android_gles_jni_GLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_GLImpl.cpp
@@ -8490,7 +8490,7 @@
 
 static const char *classPathName = "com/google/android/gles_jni/GLImpl";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nativeClassInit", "()V", (void*)nativeClassInit },
 {"glActiveTexture", "(I)V", (void *) android_glActiveTexture__I },
 {"glAlphaFunc", "(IF)V", (void *) android_glAlphaFunc__IF },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 664e621..148e7c1 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -65,6 +65,7 @@
     <protected-broadcast android:name="android.intent.action.NEW_OUTGOING_CALL" />
     <protected-broadcast android:name="android.intent.action.REBOOT" />
     <protected-broadcast android:name="android.intent.action.DOCK_EVENT" />
+    <protected-broadcast android:name="android.intent.action.THERMAL_EVENT" />
     <protected-broadcast android:name="android.intent.action.MASTER_CLEAR_NOTIFICATION" />
     <protected-broadcast android:name="android.intent.action.USER_ADDED" />
     <protected-broadcast android:name="android.intent.action.USER_REMOVED" />
@@ -188,7 +189,7 @@
     <protected-broadcast android:name="android.hardware.usb.action.USB_STATE" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_PORT_CHANGED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
-    <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_ATTACHED" />
+    <protected-broadcast android:name="android.hardware.usb.action.USB_ACCESSORY_DETACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
     <protected-broadcast android:name="android.hardware.usb.action.USB_DEVICE_DETACHED" />
 
@@ -1714,7 +1715,7 @@
         android:protectionLevel="signature|privileged" />
 
     <!-- Allows applications to change network connectivity state.
-         <p>Protection level: normal
+         <p>Protection level: signature
     -->
     <permission android:name="android.permission.CHANGE_NETWORK_STATE"
         android:description="@string/permdesc_changeNetworkState"
@@ -2529,6 +2530,12 @@
         android:label="@string/permlab_access_notification_policy"
         android:protectionLevel="normal" />
 
+    <!-- Allows modification of do not disturb rules and policies. Only allowed for system
+        processes.
+        @hide -->
+    <permission android:name="android.permission.MANAGE_NOTIFICATIONS"
+                android:protectionLevel="signature" />
+
     <!-- Allows access to keyguard secure storage.  Only allowed for system processes.
         @hide -->
     <permission android:name="android.permission.ACCESS_KEYGUARD_SECURE_STORAGE"
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_background_material.xml
similarity index 87%
rename from core/res/res/color/btn_colored_material.xml
rename to core/res/res/color/btn_colored_background_material.xml
index b45f824..b7f0ef5 100644
--- a/core/res/res/color/btn_colored_material.xml
+++ b/core/res/res/color/btn_colored_background_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 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.
@@ -14,6 +14,7 @@
      limitations under the License.
 -->
 
+<!-- Used for tha background of a bordered colored button. -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/color/btn_colored_borderless_text_material.xml
similarity index 78%
copy from core/res/res/color/btn_colored_material.xml
copy to core/res/res/color/btn_colored_borderless_text_material.xml
index b45f824..ee5a90c 100644
--- a/core/res/res/color/btn_colored_material.xml
+++ b/core/res/res/color/btn_colored_borderless_text_material.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 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.
@@ -14,9 +14,10 @@
      limitations under the License.
 -->
 
+<!-- Used for the text of a borderless colored button. -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="?attr/colorButtonNormal" />
-    <item android:color="?attr/colorAccent" />
+          android:color="?attr/textColorSecondary" />
+    <item android:color="?attr/colorAccent"/>
 </selector>
diff --git a/core/res/res/color/btn_colored_text_material.xml b/core/res/res/color/btn_colored_text_material.xml
index 950d04a..c80fea6 100644
--- a/core/res/res/color/btn_colored_text_material.xml
+++ b/core/res/res/color/btn_colored_text_material.xml
@@ -14,9 +14,10 @@
      limitations under the License.
 -->
 
+<!-- Used for the text of a bordered colored button. -->
 <selector xmlns:android="http://schemas.android.com/apk/res/android">
     <item android:state_enabled="false"
           android:alpha="?attr/disabledAlpha"
-          android:color="?attr/textColorSecondary" />
-    <item android:color="?attr/colorAccent"/>
+          android:color="?attr/textColorPrimary" />
+    <item android:color="?attr/textColorPrimaryInverse" />
 </selector>
diff --git a/core/res/res/drawable/btn_colored_material.xml b/core/res/res/drawable/btn_colored_material.xml
index 81cbe39..c3c5760 100644
--- a/core/res/res/drawable/btn_colored_material.xml
+++ b/core/res/res/drawable/btn_colored_material.xml
@@ -22,7 +22,7 @@
     <ripple android:color="?attr/colorControlHighlight">
         <item>
             <shape android:shape="rectangle"
-                   android:tint="@color/btn_colored_material">
+                   android:tint="@color/btn_colored_background_material">
                 <corners android:radius="@dimen/control_corner_material" />
                 <solid android:color="@color/white" />
                 <padding android:left="@dimen/button_padding_horizontal_material"
diff --git a/core/res/res/color/btn_colored_material.xml b/core/res/res/layout/docked_stack_divider.xml
similarity index 65%
copy from core/res/res/color/btn_colored_material.xml
copy to core/res/res/layout/docked_stack_divider.xml
index b45f824..aa6e68d 100644
--- a/core/res/res/color/btn_colored_material.xml
+++ b/core/res/res/layout/docked_stack_divider.xml
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2014 The Android Open Source Project
+<!-- Copyright (C) 2015 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.
@@ -14,9 +14,8 @@
      limitations under the License.
 -->
 
-<selector xmlns:android="http://schemas.android.com/apk/res/android">
-    <item android:state_enabled="false"
-          android:alpha="?attr/disabledAlpha"
-          android:color="?attr/colorButtonNormal" />
-    <item android:color="?attr/colorAccent" />
-</selector>
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="@dimen/docked_stack_divider_thickness"
+        android:layout_height="match_parent"
+        android:background="@android:color/black"
+        />
diff --git a/core/res/res/layout/number_picker_material.xml b/core/res/res/layout/number_picker_material.xml
index 47edec4..b045585 100644
--- a/core/res/res/layout/number_picker_material.xml
+++ b/core/res/res/layout/number_picker_material.xml
@@ -22,4 +22,4 @@
       android:gravity="center"
       android:singleLine="true"
       android:background="@null"
-      android:textAppearance="@style/TextAppearance.Material.Caption" />
+      android:textAppearance="@style/TextAppearance.Material.Body1" />
diff --git a/core/res/res/layout/popup_menu_header_item_layout.xml b/core/res/res/layout/popup_menu_header_item_layout.xml
new file mode 100644
index 0000000..5879f85f
--- /dev/null
+++ b/core/res/res/layout/popup_menu_header_item_layout.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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="?attr/dropdownListPreferredItemHeight"
+    android:minWidth="196dip"
+    android:paddingStart="16dip"
+    android:paddingEnd="16dip">
+
+    <TextView
+        android:id="@+id/title"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?attr/textAppearancePopupMenuHeader"
+        android:layout_gravity="center_vertical"
+        android:singleLine="true"
+        android:ellipsize="marquee"
+        android:fadingEdge="horizontal"
+        android:textAlignment="viewStart" />
+
+</FrameLayout>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index a08f040..2f1627b 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -227,23 +227,23 @@
     <string name="user_owner_label" msgid="2804351898001038951">"Persoonlik"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Werk"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakte"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"gaan by jou kontakte in"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"in te gaan by jou kontakte"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Ligging"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"verkry toegang tot hierdie toestel se ligging"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"toegang te verkry tot hierdie toestel se ligging"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalender"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"gaan by jou kalender in"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"by jou kalender in te gaan"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"stuur en bekyk SMS-boodskappe"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS-boodskappe te stuur en te bekyk"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Stoor"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"verkry toegang tot foto\'s, media en lêers op jou toestel"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"toegang te verkry tot foto\'s, media en lêers op jou toestel"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofoon"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"neem oudio op"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"oudio op te neem"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"neem foto\'s en neem video op"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"foto\'s en video te neem"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Foon"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"maak en bestuur foonoproepe"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"foonoproepe te maak en te bestuur"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Liggaamsensors"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"kry toegang tot sensordata oor jou lewenstekens"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"toegang te verkry tot sensordata oor jou lewenstekens"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Haal venster-inhoud op"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Ondersoek die inhoud van \'n venster waarmee jy interaksie het."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Skakel Verken deur raak aan"</string>
@@ -272,7 +272,7 @@
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Laat die program toe om seluitsending-boodskappe te lees wat deur jou toestel ontvang word. Seluitsending-waarskuwings word in sommige plekke afgelewer om jou van noodsituasies te waarsku. Kwaadwillige programme mag inmeng met die prestasie of die werking van jou toestel wanneer \'n noodgeval se seluitsending ontvang word."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lees ingetekende nuus"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Laat die program toe om details oor die tans gesinkroniseerde strome te kry."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"stuur en bekyk SMS-boodskappe"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"SMS-boodskappe te stuur en te bekyk"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Laat die program toe om SMS-boodskappe te stuur. Dit kan tot onverwagse heffings lei. Kwaadwillige programme kan jou geld kos deur boodskappe sonder jou bevestiging te stuur."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"lees jou teksboodskappe (SMS of MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Laat die program toe om SMS-boodskappe wat op jou tablet of SIM-kaart gestoor is, te lees. Dit laat die program toe om alle SMS-boodskappe te lees, ongeag van die inhoud of vertroulikheid daarvan."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index cd6bb4b..7b05612 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -231,7 +231,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontakty"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"přístup ke kontaktům"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Poloha"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"přístup k poloze tohoto zařízení"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendář"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"přístup ke kalendáři"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index e718935..60f0502 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -493,8 +493,8 @@
     <string name="permdesc_bindCarrierMessagingService" msgid="2762882888502113944">"Dette giver indehaveren mulighed for at knytte sig til det øverste grænsefladeniveau for et mobilselskabs beskedtjeneste. Dette bør ikke være nødvendigt i normale apps."</string>
     <string name="permlab_bindCarrierServices" msgid="3233108656245526783">"knytte til tjenester fra mobilselskabet"</string>
     <string name="permdesc_bindCarrierServices" msgid="1391552602551084192">"Tillader, at brugeren knytter sig til tjenester fra mobilselskabet. Dette bør aldrig være nødvendigt for almindelige apps."</string>
-    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"Adgang til Vil ikke forstyrres"</string>
-    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Vil ikke forstyrres."</string>
+    <string name="permlab_access_notification_policy" msgid="4247510821662059671">"have adgang til Forstyr ikke"</string>
+    <string name="permdesc_access_notification_policy" msgid="3296832375218749580">"Giver appen tilladelse til at læse og skrive konfigurationen af Forstyr ikke."</string>
     <string name="policylab_limitPassword" msgid="4497420728857585791">"Angiv regler for adgangskoder"</string>
     <string name="policydesc_limitPassword" msgid="2502021457917874968">"Kontrollér længden samt tilladte tegn i adgangskoder og pinkoder til skærmlåsen."</string>
     <string name="policylab_watchLogin" msgid="914130646942199503">"Overvåg forsøg på oplåsning af skærm"</string>
@@ -1471,10 +1471,10 @@
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Indtil <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Indtil du slår denne indstilling fra"</string>
-    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Vil ikke forstyrres\" fra"</string>
+    <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Indtil du slår \"Forstyr ikke\" fra"</string>
     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
     <string name="toolbar_collapse_description" msgid="2821479483960330739">"Skjul"</string>
-    <string name="zen_mode_feature_name" msgid="5254089399895895004">"Vil ikke forstyrres"</string>
+    <string name="zen_mode_feature_name" msgid="5254089399895895004">"Forstyr ikke"</string>
     <string name="zen_mode_downtime_feature_name" msgid="2626974636779860146">"Nedetid"</string>
     <string name="zen_mode_default_weeknights_name" msgid="3081318299464998143">"Hverdagsaften"</string>
     <string name="zen_mode_default_weekends_name" msgid="2786495801019345244">"Weekend"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index 2c7a64d..8e7193a 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -227,23 +227,23 @@
     <string name="user_owner_label" msgid="2804351898001038951">"Pertsonalak"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Lana"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktuak"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"Atzitu kontaktuak"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"kontaktuak atzitzeko"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Kokapena"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"Atzitu gailuaren kokapena"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"gailuaren kokapena atzitzeko"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Egutegia"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"Atzitu egutegia"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"egutegia atzitzeko"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS mezuak"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"Bidali eta ikusi SMS mezuak"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS mezuak bidaltzeko eta ikusteko"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Memoria"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"Atzitu gailuko argazkiak, multimedia-elementuak eta fitxategiak"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"gailuko argazkiak, multimedia-elementuak eta fitxategiak atzitzeko"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofonoa"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"Grabatu audioa"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"audioa grabatzeko"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"Atera argazkiak eta grabatu bideoak"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"argazkiak ateratzeko eta bideoak grabatzeko"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefonoa"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"Egin eta kudeatu telefono-deiak"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"telefono-deiak egiteko eta kudeatzeko"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Gorputz-sentsoreak"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"Atzitu bizi-konstanteei buruzko sentsore-datuak"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"bizi-konstanteei buruzko sentsore-datuak atzitzeko"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Eskuratu leihoko edukia"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Arakatu irekita daukazun leihoko edukia."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Aktibatu ukipen bidez arakatzeko eginbidea"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 6c03159..45d9dc3 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -144,14 +144,14 @@
     <string name="httpErrorOk" msgid="1191919378083472204">"تأیید"</string>
     <string name="httpError" msgid="7956392511146698522">"خطایی در شبکه وجود داشت."</string>
     <string name="httpErrorLookup" msgid="4711687456111963163">"‏URL پیدا نشد."</string>
-    <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"‏طرح کلی تأیید اعتبار سایت پشتیبانی نمی‎شود."</string>
+    <string name="httpErrorUnsupportedAuthScheme" msgid="6299980280442076799">"‏طرح کلی تأیید اعتبار سایت پشتیبانی نمی‌‎شود."</string>
     <string name="httpErrorAuth" msgid="1435065629438044534">"تأیید اعتبار انجام نشد."</string>
     <string name="httpErrorProxyAuth" msgid="1788207010559081331">"تأیید اعتبار از طریق سرور پروکسی انجام نشد."</string>
     <string name="httpErrorConnect" msgid="8714273236364640549">"اتصال به سرور انجام نشد."</string>
     <string name="httpErrorIO" msgid="2340558197489302188">"برقراری ارتباط با سرور ممکن نبود. بعداً دوباره امتحان کنید."</string>
     <string name="httpErrorTimeout" msgid="4743403703762883954">"زمان اتصال به سرور تمام شده است."</string>
     <string name="httpErrorRedirectLoop" msgid="8679596090392779516">"این صفحه دارای تعداد بسیار زیادی تغییر مسیر سرور است."</string>
-    <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"‏پروتکل پشتیبانی نمی‎شود."</string>
+    <string name="httpErrorUnsupportedScheme" msgid="5015730812906192208">"‏پروتکل پشتیبانی نمی‌‎شود."</string>
     <string name="httpErrorFailedSslHandshake" msgid="96549606000658641">"اتصال امن ایجاد نشد."</string>
     <string name="httpErrorBadUrl" msgid="3636929722728881972">"‏بدلیل نامعتبر بودن URL، باز کردن صفحه ممکن نیست."</string>
     <string name="httpErrorFile" msgid="2170788515052558676">"دسترسی به فایل انجام نشد."</string>
@@ -781,13 +781,13 @@
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"به برنامه اجازه می‌دهد تا سابقه یا نشانک‌های ذخیره شده مرورگر در تلویزیون شما را تغییر دهد. شاید به برنامه اجازه دهد تا داده‌های «مرورگر» را پاک کند یا تغییر دهد. توجه: این مجوز شاید توسط مرورگرهای شخص ثالث یا سایر برنامه‌ها با قابلیت‌های مرور وب اجرا شود."</string>
     <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"به برنامه اجازه می‌دهد سابقه مرورگر یا نشانک‌های ذخیره شده در تلفن شما را اصلاح کند. این ویژگی ممکن است به برنامه اجازه دهد داده‌های مرورگر را حذف یا اصلاح کند. توجه: این مجوز ممکن است توسط مرورگرهای شخص ثالث یا سایر برنامه‌های دارای قابلیت مرور وب قابل اجرا نباشد."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"تنظیم یک هشدار"</string>
-    <string name="permdesc_setAlarm" msgid="316392039157473848">"‏به برنامه اجازه می‎دهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامه‎های ساعت زنگدار نمی‎توانند این ویژگی را اعمال کنند."</string>
+    <string name="permdesc_setAlarm" msgid="316392039157473848">"‏به برنامه اجازه می‎دهد تا هشداری را در برنامه ساعت زنگدار نصب شده تنظیم کند. برخی از برنامه‎های ساعت زنگدار نمی‌‎توانند این ویژگی را اعمال کنند."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"افزودن پست صوتی"</string>
     <string name="permdesc_addVoicemail" msgid="6604508651428252437">"به برنامه اجازه می‌دهد تا پیام‌ها را به صندوق دریافت پست صوتی شما اضافه کند."</string>
     <string name="permlab_writeGeolocationPermissions" msgid="5962224158955273932">"تغییر مجوزهای مکان جغرافیایی مرورگر"</string>
     <string name="permdesc_writeGeolocationPermissions" msgid="1083743234522638747">"‏به برنامه اجازه می‎دهد تا مجوزهای جغرافیایی مرورگر را تغییر دهد. برنامه‎های مخرب می‎توانند از آن استفاده کنند تا اطلاعات موقعیت مکانی را به سایت‌های وب کتابخانه بفرستند."</string>
     <string name="save_password_message" msgid="767344687139195790">"می‌خواهید مرورگر این رمز ورود را به خاطر داشته باشد؟"</string>
-    <string name="save_password_notnow" msgid="6389675316706699758">"الآن نه"</string>
+    <string name="save_password_notnow" msgid="6389675316706699758">"اکنون نه"</string>
     <string name="save_password_remember" msgid="6491879678996749466">"به خاطر سپردن"</string>
     <string name="save_password_never" msgid="8274330296785855105">"هیچ‌وقت"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"شما اجازه بازکردن این صفحه را ندارید."</string>
@@ -894,16 +894,16 @@
     <string name="clearDefaultHintMsg" msgid="3252584689512077257">"‏پیش‌فرض را در تنظیمات سیستم&gt; برنامه‎ها&gt; مورد دانلود شده پاک کنید."</string>
     <string name="chooseActivity" msgid="7486876147751803333">"انتخاب عملکرد"</string>
     <string name="chooseUsbActivity" msgid="6894748416073583509">"‏انتخاب برنامه برای دستگاه USB"</string>
-    <string name="noApplications" msgid="2991814273936504689">"‏هیچ برنامه‌ای نمی‎تواند این کار را انجام دهد."</string>
+    <string name="noApplications" msgid="2991814273936504689">"‏هیچ برنامه‌ای نمی‌‎تواند این کار را انجام دهد."</string>
     <string name="aerr_title" msgid="1905800560317137752"></string>
     <string name="aerr_application" msgid="932628488013092776">"متأسفانه، <xliff:g id="APPLICATION">%1$s</xliff:g> متوقف شده است."</string>
     <string name="aerr_process" msgid="4507058997035697579">"متأسفانه، پردازش <xliff:g id="PROCESS">%1$s</xliff:g> متوقف شده است."</string>
     <string name="aerr_process_silence" msgid="4226685530196000222">"تا را‌ه‌اندازی مجدد، خرابی‌ها از <xliff:g id="PROCESS">%1$s</xliff:g> نادیده گرفته شوند."</string>
     <string name="anr_title" msgid="4351948481459135709"></string>
-    <string name="anr_activity_application" msgid="1904477189057199066">"‏<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمی‎دهد.\n\nآیا می‎خواهید آنرا ببندید؟"</string>
-    <string name="anr_activity_process" msgid="5776209883299089767">"‏فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمی‎دهد.\n\nآیا می‎خواهید آن را ببندید؟"</string>
-    <string name="anr_application_process" msgid="8941757607340481057">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمی‎دهد. آیا می‎خواهید آن را ببندید؟"</string>
-    <string name="anr_process" msgid="6513209874880517125">"‏روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمی‎دهد. \n\nآیا می‎خواهید آن را ببندید؟"</string>
+    <string name="anr_activity_application" msgid="1904477189057199066">"‏<xliff:g id="APPLICATION">%2$s</xliff:g> پاسخ نمی‌‎دهد.\n\nآیا می‎خواهید آنرا ببندید؟"</string>
+    <string name="anr_activity_process" msgid="5776209883299089767">"‏فعالیت <xliff:g id="ACTIVITY">%1$s</xliff:g> پاسخ نمی‌‎دهد.\n\nآیا می‎خواهید آن را ببندید؟"</string>
+    <string name="anr_application_process" msgid="8941757607340481057">"‏<xliff:g id="APPLICATION">%1$s</xliff:g> پاسخ نمی‌‎دهد. آیا می‎خواهید آن را ببندید؟"</string>
+    <string name="anr_process" msgid="6513209874880517125">"‏روند <xliff:g id="PROCESS">%1$s</xliff:g> پاسخ نمی‌‎دهد. \n\nآیا می‎خواهید آن را ببندید؟"</string>
     <string name="force_close" msgid="8346072094521265605">"تأیید"</string>
     <string name="report" msgid="4060218260984795706">"گزارش"</string>
     <string name="wait" msgid="7147118217226317732">"منتظر بمانید"</string>
@@ -1006,14 +1006,14 @@
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"همیشه غیرمجاز"</string>
     <string name="sim_removed_title" msgid="6227712319223226185">"سیم کارت برداشته شد"</string>
     <string name="sim_removed_message" msgid="5450336489923274918">"تا زمانی که با یک سیم‌کارت معتبر دوباره راه‌اندازی نکنید شبکه تلفن همراه غیر قابل‌ دسترس خواهد بود."</string>
-    <string name="sim_done_button" msgid="827949989369963775">"انجام شد"</string>
+    <string name="sim_done_button" msgid="827949989369963775">"تمام"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"سیم کارت اضافه شد"</string>
     <string name="sim_added_message" msgid="7797975656153714319">"برای دسترسی به شبکه تلفن همراه، دستگاهتان را مجدداً راه‌اندازی کنید."</string>
     <string name="sim_restart_button" msgid="4722407842815232347">"راه‌اندازی مجدد"</string>
     <string name="time_picker_dialog_title" msgid="8349362623068819295">"تنظیم زمان"</string>
     <string name="date_picker_dialog_title" msgid="5879450659453782278">"تاریخ تنظیم"</string>
     <string name="date_time_set" msgid="5777075614321087758">"تنظیم"</string>
-    <string name="date_time_done" msgid="2507683751759308828">"انجام شد"</string>
+    <string name="date_time_done" msgid="2507683751759308828">"تمام"</string>
     <string name="perms_new_perm_prefix" msgid="8257740710754301407"><font size="12" fgcolor="#ff33b5e5">"جدید: "</font></string>
     <string name="perms_description_app" msgid="5139836143293299417">"ارائه شده توسط <xliff:g id="APP_NAME">%1$s</xliff:g> ."</string>
     <string name="no_permissions" msgid="7283357728219338112">"مجوزی لازم نیست"</string>
@@ -1085,7 +1085,7 @@
     <string name="ime_action_search" msgid="658110271822807811">"جستجو"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"ارسال"</string>
     <string name="ime_action_next" msgid="3138843904009813834">"بعدی"</string>
-    <string name="ime_action_done" msgid="8971516117910934605">"انجام شد"</string>
+    <string name="ime_action_done" msgid="8971516117910934605">"تمام"</string>
     <string name="ime_action_previous" msgid="1443550039250105948">"قبلی"</string>
     <string name="ime_action_default" msgid="2840921885558045721">"اجرا کردن"</string>
     <string name="dial_number_using" msgid="5789176425167573586">"شماره گیری \nبا استفاده از <xliff:g id="NUMBER">%s</xliff:g>"</string>
@@ -1131,7 +1131,7 @@
       <item quantity="one"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
       <item quantity="other"><xliff:g id="INDEX">%d</xliff:g> از <xliff:g id="TOTAL">%d</xliff:g></item>
     </plurals>
-    <string name="action_mode_done" msgid="7217581640461922289">"انجام شد"</string>
+    <string name="action_mode_done" msgid="7217581640461922289">"تمام"</string>
     <string name="progress_erasing" product="nosdcard" msgid="4521573321524340058">"‏در حال پاک کردن حافظهٔ USB..."</string>
     <string name="progress_erasing" product="default" msgid="6596988875507043042">"‏در حال پاک کردن کارت SD..."</string>
     <string name="share" msgid="1778686618230011964">"اشتراک‌گذاری"</string>
@@ -1173,7 +1173,7 @@
     <string name="keyboardview_keycode_alt" msgid="4856868820040051939">"Alt"</string>
     <string name="keyboardview_keycode_cancel" msgid="1203984017245783244">"لغو"</string>
     <string name="keyboardview_keycode_delete" msgid="3337914833206635744">"Delete"</string>
-    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"انجام شد"</string>
+    <string name="keyboardview_keycode_done" msgid="1992571118466679775">"تمام"</string>
     <string name="keyboardview_keycode_mode_change" msgid="4547387741906537519">"تغییر حالت"</string>
     <string name="keyboardview_keycode_shift" msgid="2270748814315147690">"Shift"</string>
     <string name="keyboardview_keycode_enter" msgid="2985864015076059467">"Enter"</string>
@@ -1416,7 +1416,7 @@
     <string name="immersive_cling_title" msgid="8394201622932303336">"مشاهده در حالت تمام صفحه"</string>
     <string name="immersive_cling_description" msgid="3482371193207536040">"برای خروج، انگشتتان را از بالای صفحه به پایین بکشید."</string>
     <string name="immersive_cling_positive" msgid="5016839404568297683">"متوجه شدم"</string>
-    <string name="done_label" msgid="2093726099505892398">"انجام شد"</string>
+    <string name="done_label" msgid="2093726099505892398">"تمام"</string>
     <string name="hour_picker_description" msgid="6698199186859736512">"لغزنده دایره‌ای ساعت"</string>
     <string name="minute_picker_description" msgid="8606010966873791190">"لغزنده دایره‌ای دقیقه"</string>
     <string name="select_hours" msgid="6043079511766008245">"انتخاب ساعت"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 7b5ca29..c32add0 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -229,7 +229,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contactos"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acceder aos teus contactos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Localización"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"acceso á localización deste dispositivo"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"acceder á localización deste dispositivo"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendario"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceder ao teu calendario"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 9392997..6281abf 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -229,8 +229,8 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"સંપર્કો"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"તમારા સંપર્કોને ઍક્સેસ કરો"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"સ્થાન"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરો"</string>
-    <string name="permgrouplab_calendar" msgid="5863508437783683902">"કૅલેન્ડર"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"આ ઉપકરણના સ્થાનને ઍક્સેસ કરવાની"</string>
+    <string name="permgrouplab_calendar" msgid="5863508437783683902">"કેલેન્ડર"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"તમારા કેલેન્ડરને ઍક્સેસ કરવાની"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS સંદેશા મોકલો અને જોવાની"</string>
@@ -326,14 +326,14 @@
     <string name="permdesc_writeCallLog" product="default" msgid="683941736352787842">"એપ્લિકેશનને ઇનકમિંગ અને આઉટગોઇંગ કૉલ્સ વિશેનાં ડેટા સહિત, તમારા ફોનના કૉલ લૉગને સંશોધિત કરવાની મંજૂરી આપે છે. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો આનો ઉપયોગ તમારા કૉલ લૉગને કાઢી નાખવા અથવા સંશોધિત માટે કરી શકે છે."</string>
     <string name="permlab_bodySensors" msgid="4871091374767171066">"બૉડી સેન્સર્સ (જેમ કે હાર્ટ રેટ મૉનિટર્સ)"</string>
     <string name="permdesc_bodySensors" product="default" msgid="4380015021754180431">"એપ્લિકેશનને તમારી હૃદય ગતિ જેવી તમારી શારીરિક સ્થિતિને મૉનિટર કરતાં સેન્સર્સથી ડેટા ઍક્સેસ કરવાની મંજૂરી આપે છે."</string>
-    <string name="permlab_readCalendar" msgid="5972727560257612398">"કૅલેન્ડર ઇવેન્ટ્સ વત્તા ગોપનીયતા માહિતી વાંચો"</string>
-    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
-    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
-    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર સંગ્રહિત તમામ કૅલેન્ડર ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કૅલેન્ડર ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
-    <string name="permlab_writeCalendar" msgid="8438874755193825647">"કૅલેન્ડર ઇવેન્ટ્સ ઉમેરો અથવા સંશોધિત કરો અને માલિકની જાણ બહાર અતિથિઓને ઇમેઇલ મોકલો"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
-    <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કૅલેન્ડર માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
+    <string name="permlab_readCalendar" msgid="5972727560257612398">"કેલેન્ડર  ઇવેન્ટ્સ વત્તા ગોપનીયતા માહિતી વાંચો"</string>
+    <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર સંગ્રહિત તમામ કેલેન્ડર  ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર  ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
+    <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર સંગ્રહિત તમામ કેલેન્ડર  ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર  ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
+    <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર સંગ્રહિત તમામ કેલેન્ડર  ઇવેન્ટ્સ વાંચવાની મંજૂરી આપે છે. આ એપ્લિકેશનને તમારા કેલેન્ડર  ડેટાને શેર કરવા કે સાચવવાની મંજૂરી આપી શકે છે, પછી ભલે ગોપનીયતા અથવા સંવેદિતા કોઈપણ હોય."</string>
+    <string name="permlab_writeCalendar" msgid="8438874755193825647">"કેલેન્ડર  ઇવેન્ટ્સ ઉમેરો અથવા સંશોધિત કરો અને માલિકની જાણ બહાર અતિથિઓને ઇમેઇલ મોકલો"</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટેબ્લેટ પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર  માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
+    <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ટીવી પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર  માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"એપ્લિકેશનને મિત્રોના અથવા સહકાર્યકરો સહિત તમારા ફોન પર તમે સંશોધિત કરી શકો તે ઇવેન્ટ્સ ઉમેરવા, દૂર કરવા, બદલવાની મંજૂરી આપે છે. આ એપ્લિકેશનને કેલેન્ડર  માલિક તરફથી આવતાં હોય તેવા સંદેશા મોકલવાની અથવા માલિકની જાણ વિના ઇવેન્ટ્સ સંશોધિત કરવાની મંજૂરી આપી શકે છે."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરો"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"એપ્લિકેશનને વધારાના સ્થાન પ્રદાતા આદેશોને ઍક્સેસ કરવાની મંજૂરી આપે છે. આ એપ્લિકેશનને GPS અથવા અન્ય સ્થાન સ્રોતોના ઓપરેશનમાં દખલ કરવાની મંજૂરી આપી શકે છે."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"નિશ્ચિત સ્થાન (GPS અને નેટવર્ક-આધારિત)"</string>
diff --git a/core/res/res/values-it-watch/strings.xml b/core/res/res/values-it-watch/strings.xml
index c348e48..aa6a4be 100644
--- a/core/res/res/values-it-watch/strings.xml
+++ b/core/res/res/values-it-watch/strings.xml
@@ -29,7 +29,7 @@
     <string name="permgrouplab_storagewear" msgid="1003807594193602313">"accedere a foto, contenuti multimediali e file sull\'orologio"</string>
     <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"registrare audio"</string>
     <string name="permgrouplab_camerawear" msgid="4543951283103407017">"scattare foto e registrare video"</string>
-    <string name="permgrouplab_phonewear" msgid="134365036753766126">"fare e gestire telefonate"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"eseguire e gestire le telefonate"</string>
     <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string>
     <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"avere la funzione di barra di stato"</string>
     <string name="permlab_bodySensorswear" msgid="7857941041202791873">"accedere ai sensori (come il cardiofrequenzimetro)"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index 4271287..72b1c54 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -239,11 +239,11 @@
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfono"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"registrare audio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Fotocamera"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"acquisire foto e registrare video"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"scattare foto e registrare video"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefono"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"eseguire e gestire le telefonate"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensori per il corpo"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedere ai dati dei sensori sui tuoi parametri vitali"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accedere ai dati dei sensori relativi ai tuoi parametri vitali"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperare contenuti della finestra"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Esaminare i contenuti di una finestra con cui interagisci."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Attivare Esplora al tocco"</string>
@@ -272,7 +272,7 @@
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Consente all\'applicazione di leggere i messaggi cell broadcast ricevuti dal dispositivo. Gli avvisi cell broadcast vengono trasmessi in alcune località per avvertire di eventuali situazioni di emergenza. Le applicazioni dannose potrebbero interferire con il rendimento o con il funzionamento del dispositivo quando si riceve un messaggio cell broadcast di emergenza."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"lettura feed sottoscritti"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Consente all\'applicazione di ottenere dettagli sui feed attualmente sincronizzati."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"invio e lettura di SMS"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"inviare e visualizzare SMS"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Consente all\'applicazione di inviare messaggi SMS. Ciò potrebbe comportare costi imprevisti. Applicazioni dannose potrebbero generare dei costi inviando messaggi senza la tua conferma."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"lettura messaggi di testo personali (SMS o MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Consente all\'applicazione di leggere i messaggi SMS memorizzati sul tablet o sulla scheda SIM. Ciò consente all\'applicazione di leggere tutti i messaggi SMS, indipendentemente dai contenuti o dal livello di riservatezza."</string>
@@ -342,7 +342,7 @@
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Consente all\'applicazione di ottenere la tua posizione approssimativa. Questa posizione viene ottenuta da servizi di localizzazione utilizzando fonti di geolocalizzazione delle reti come ripetitori di telefonia mobile e Wi-Fi. Questi servizi di localizzazione devono essere attivi e disponibili sul dispositivo per poter essere utilizzati dall\'applicazione. Le applicazioni potrebbero utilizzare questa autorizzazione per stabilire la tua posizione approssimativa."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modifica impostazioni audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Consente all\'applicazione di modificare le impostazioni audio globali, come il volume e quale altoparlante viene utilizzato per l\'uscita."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"registrazione audio"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"registrare audio"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Consente all\'applicazione di registrare audio con il microfono. Questa autorizzazione consente all\'applicazione di registrare audio in qualsiasi momento senza la tua conferma."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"comunicazione SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Consente all\'app di inviare comandi alla SIM. Questo è molto pericoloso."</string>
diff --git a/core/res/res/values-ja-watch/strings.xml b/core/res/res/values-ja-watch/strings.xml
index 3248041..82c3ffd 100644
--- a/core/res/res/values-ja-watch/strings.xml
+++ b/core/res/res/values-ja-watch/strings.xml
@@ -37,7 +37,7 @@
     <string name="permlab_accessCoarseLocationwear" msgid="5880746016230166090">"おおよその位置情報(ネットワーク基地局)へのアクセス"</string>
     <string name="permlab_sim_communicationwear" msgid="1899198085342781874">"SIMへのコマンド送信"</string>
     <string name="permlab_createNetworkSocketswear" msgid="6467042386273822913">"ネットワークへのフルアクセス"</string>
-    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロフィールの所有者と端末の所有者の管理"</string>
+    <string name="permlab_manageProfileAndDeviceOwnerswear" msgid="7313340516937821847">"プロファイルの所有者と端末の所有者の管理"</string>
     <string name="permlab_changeWimaxStatewear" msgid="3828470843939853744">"WiMAX状態の変更"</string>
     <string name="permlab_handoverStatuswear" msgid="4835786819716499249">"Androidビーム転送のステータスの受信"</string>
     <string name="permlab_route_media_outputwear" msgid="8737024341474587192">"メディア出力のルーティング"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 545b963..135c7ea 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -282,8 +282,8 @@
     <string name="permdesc_receiveWapPush" msgid="748232190220583385">"WAPメッセージの受信と処理をアプリに許可します。これにより、アプリが端末に届いたメッセージを表示することなく監視または削除できるようになります。"</string>
     <string name="permlab_getTasks" msgid="6466095396623933906">"実行中のアプリの取得"</string>
     <string name="permdesc_getTasks" msgid="7454215995847658102">"現在実行中または最近実行したタスクに関する情報の取得をアプリに許可します。これにより、その端末でどのアプリを使用しているかをアプリから識別できるようになる可能性があります。"</string>
-    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"プロフィールの所有者と端末の所有者の管理"</string>
-    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"プロフィールの所有者と端末の所有者の設定をアプリに許可します。"</string>
+    <string name="permlab_manageProfileAndDeviceOwners" msgid="5979288447973722097">"プロファイルの所有者と端末の所有者の管理"</string>
+    <string name="permdesc_manageProfileAndDeviceOwners" msgid="106894851498657169">"プロファイルの所有者と端末の所有者の設定をアプリに許可します。"</string>
     <string name="permlab_reorderTasks" msgid="2018575526934422779">"実行中のアプリの順序変更"</string>
     <string name="permdesc_reorderTasks" msgid="7734217754877439351">"タスクをフォアグラウンドやバックグラウンドに移動することをアプリに許可します。これにより、アプリがユーザーからの入力なしでこの処理を実行する可能性があります。"</string>
     <string name="permlab_enableCarMode" msgid="5684504058192921098">"運転モードの有効化"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index d39ee05..7af4df0 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -229,7 +229,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контактілер"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"контактілерге кіру"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Орын"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орнына кіру"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"бұл құрылғының орналасқан жерін көру"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнтізбе"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"күнтізбеге кіру"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index e7e43f0..f20551d 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -229,7 +229,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Байланыштар"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"байланыштарыңызга уруксат"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Жайгашкан жер"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"бул түзмөктүн жайгашкан жерине кирүү"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"бул түзмөктүн жайгашкан жери тууралуу дайындарды көрүү"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Күнбарак"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"жылнаамаңызды пайдалануу"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index f10fb19..a41be56 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -227,23 +227,23 @@
     <string name="user_owner_label" msgid="2804351898001038951">"Лични"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Работа"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапи до контактите"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"пристапува до контактите"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"да пристапува до локацијата на овој уред"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"пристапува до локацијата на овој уред"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапи до календарот"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"пристапува до календарот"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"СМС"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"испраќа и прикажува СМС-пораки"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Меморија"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"пристапува до фотографии, медиуми и датотеки на уредот"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"пристапува до фотографии, аудио-видео и датотеки на уредот"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снимај аудио"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Фотоапарат"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"фотографирај и снимај видео"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"фотографира и снима видео"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"повикувај и управувај со телефонски повици"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"упатува и управува со телефонски повици"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Телесни сензори"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"пристапи до податоците од сензорите за виталните знаци"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"пристапува до податоците од сензорите за виталните знаци"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Врати содржина на прозорец"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Провери ја содржината на прозорецот со кој се комуницира."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Вклучи „Истражувај со допир“"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index a547ca7..41528d87 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -229,7 +229,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"အဆက်အသွယ်များ"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"သင့် အဆက်အသွယ်များအား ဝင်ရောက်သုံးရန်"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"တည်နေရာ"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"စက်ပစ္စည်း၏ တည်နေရာကို အသုံးပြုမည်"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"ဤစက်ပစ္စည်း၏ တည်နေရာကို ရယူ"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"ပြက္ခဒိန်"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"သင့်ပြက္ခဒိန်အား ဝင်ရောက်သုံးရန်"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"စာတိုစနစ်"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index d203a6a..2f6c8bf 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -227,23 +227,23 @@
     <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acessar seus contatos"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acessar sua agenda"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do seu dispositivo"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"grave áudio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefone"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerenciar chamadas telefônicas"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gerencie chamadas telefônicas"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acessar dados do sensor sobre seus sinais vitais"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acesse dados do sensor sobre seus sinais vitais"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar cont. da janela"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecionar o conteúdo da janela com que você está interagindo."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Ativar Explorar por toque"</string>
@@ -272,7 +272,7 @@
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite que o app obtenha detalhes sobre os feeds sincronizados no momento."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"enviar e ver mensagens SMS"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"envie e veja mensagens SMS"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite que o app envie mensagens SMS. Isso pode resultar em cobranças inesperadas. Apps maliciosos podem gerar custos através do envio de mensagens sem sua confirmação."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"ler suas mensagens de texto (SMS ou MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite que o app leia mensagens SMS armazenadas no tablet ou cartão SIM. Isso permite que o app leia todas as mensagens SMS, independentemente de seu conteúdo ou confidencialidade."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index d203a6a..2f6c8bf 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -227,23 +227,23 @@
     <string name="user_owner_label" msgid="2804351898001038951">"Pessoal"</string>
     <string name="managed_profile_label" msgid="6260850669674791528">"Trabalho"</string>
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Contatos"</string>
-    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acessar seus contatos"</string>
+    <string name="permgroupdesc_contacts" msgid="6951499528303668046">"acesse seus contatos"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Local"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"acesse o local do dispositivo"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Agenda"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acessar sua agenda"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acesse sua agenda"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"enviar e ver mensagens SMS"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Armazenamento"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do seu dispositivo"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"acesse fotos, mídia e arquivos do dispositivo"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfone"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"grave áudio"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Câmera"</string>
     <string name="permgroupdesc_camera" msgid="3250611594678347720">"tire fotos e grave vídeos"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefone"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"fazer e gerenciar chamadas telefônicas"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"faça e gerencie chamadas telefônicas"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Sensores corporais"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acessar dados do sensor sobre seus sinais vitais"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acesse dados do sensor sobre seus sinais vitais"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperar cont. da janela"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspecionar o conteúdo da janela com que você está interagindo."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Ativar Explorar por toque"</string>
@@ -272,7 +272,7 @@
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite que o app leia mensagens de difusão celular recebidas por seu dispositivo. Alertas de difusão celular são recebidos em alguns locais para avisar você de situações de emergência. Apps maliciosos podem interferir no desempenho ou funcionamento de seu dispositivo quando uma difusão celular de emergência é recebida."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"ler feeds inscritos"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite que o app obtenha detalhes sobre os feeds sincronizados no momento."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"enviar e ver mensagens SMS"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"envie e veja mensagens SMS"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite que o app envie mensagens SMS. Isso pode resultar em cobranças inesperadas. Apps maliciosos podem gerar custos através do envio de mensagens sem sua confirmação."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"ler suas mensagens de texto (SMS ou MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite que o app leia mensagens SMS armazenadas no tablet ou cartão SIM. Isso permite que o app leia todas as mensagens SMS, independentemente de seu conteúdo ou confidencialidade."</string>
diff --git a/core/res/res/values-ro-watch/strings.xml b/core/res/res/values-ro-watch/strings.xml
index e412cad..9a8e4e0 100644
--- a/core/res/res/values-ro-watch/strings.xml
+++ b/core/res/res/values-ro-watch/strings.xml
@@ -22,15 +22,15 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"Aplic. <xliff:g id="NUMBER_0">%1$d</xliff:g> din <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
     <string name="permgrouplab_sensors" msgid="202675452368612754">"Senzori"</string>
-    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"să acceseze persoanele de contact"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"acceseze persoanele de contact"</string>
     <string name="permgrouplab_locationwear" msgid="6275317222482780209">"să acceseze locația acestui ceas"</string>
-    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"să acceseze calendarul"</string>
-    <string name="permgrouplab_smswear" msgid="6849506550342974220">"să trimită și să vadă mesajele SMS"</string>
+    <string name="permgrouplab_calendarwear" msgid="441900844045065081">"acceseze calendarul"</string>
+    <string name="permgrouplab_smswear" msgid="6849506550342974220">"trimită și să vadă mesajele SMS"</string>
     <string name="permgrouplab_storagewear" msgid="1003807594193602313">"să acceseze fotografiile, conținutul media și fișierele de pe ceas"</string>
-    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"să înregistreze conținut audio"</string>
-    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"să fotografieze și să înregistreze videoclipuri"</string>
-    <string name="permgrouplab_phonewear" msgid="134365036753766126">"să inițieze să și gestioneze apeluri telefonice"</string>
-    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"să acceseze datele de la senzori despre semnele vitale"</string>
+    <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"înregistreze sunet"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"fotografieze și să înregistreze imagini"</string>
+    <string name="permgrouplab_phonewear" msgid="134365036753766126">"inițieze să și gestioneze apeluri telefonice"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"acceseze datele de la senzori despre semnele vitale"</string>
     <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"să fie bara de stare"</string>
     <string name="permlab_bodySensorswear" msgid="7857941041202791873">"să acceseze senzorii corporali (cum ar fi monitoarele cardiace)"</string>
     <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"să acceseze locația exactă (bazată pe GPS și pe rețea)"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index d215d4c..5062e76 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -135,7 +135,7 @@
     <string name="wfc_mode_wifi_preferred_summary" msgid="1994113411286935263">"Se preferă conexiunea Wi-Fi"</string>
     <string name="wfc_mode_cellular_preferred_summary" msgid="5920549484600758786">"Se preferă conexiunea mobilă"</string>
     <string name="wfc_mode_wifi_only_summary" msgid="2379919155237869320">"Numai Wi-Fi"</string>
-    <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionată"</string>
+    <string name="cfTemplateNotForwarded" msgid="1683685883841272560">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecționată"</string>
     <string name="cfTemplateForwarded" msgid="1302922117498590521">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g>"</string>
     <string name="cfTemplateForwardedTime" msgid="9206251736527085256">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> după <xliff:g id="TIME_DELAY">{2}</xliff:g> (de) secunde"</string>
     <string name="cfTemplateRegistered" msgid="5073237827620166285">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: neredirecţionat"</string>
@@ -232,19 +232,19 @@
     <string name="permgrouplab_location" msgid="7275582855722310164">"Locație"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"acceseze locația acestui dispozitiv"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Calendar"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"accesează calendarul"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"acceseze calendarul"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
-    <string name="permgroupdesc_sms" msgid="4656988620100940350">"trimite și vede mesajele SMS"</string>
+    <string name="permgroupdesc_sms" msgid="4656988620100940350">"trimită și să vadă mesajele SMS"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Stocare"</string>
     <string name="permgroupdesc_storage" msgid="637758554581589203">"acceseze fotografiile, conținutul media și fișierele de pe dispozitiv"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Microfonul"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze conținut audio"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"înregistreze sunet"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Camera foto"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze videoclipuri"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"fotografieze și să înregistreze imagini"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"inițieze și să gestioneze apeluri telefonice"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Senzori corporali"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"accesează datele înregistrate de senzori despre semnele vitale"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"acceseze datele de la senzori despre semnele vitale"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Recuperează conținutul ferestrei"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Inspectează conținutul unei ferestre cu care interacționați."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Activează funcția Explorați prin atingere"</string>
@@ -270,11 +270,11 @@
     <string name="permlab_receiveMms" msgid="1821317344668257098">"primeşte mesaje text (MMS)"</string>
     <string name="permdesc_receiveMms" msgid="533019437263212260">"Permite aplicației să primească și să proceseze mesaje MMS. Acest lucru înseamnă că aplicația ar putea monitoriza sau șterge mesajele trimise pe dispozitivul dvs. fără a vi le arăta."</string>
     <string name="permlab_readCellBroadcasts" msgid="1598328843619646166">"citeşte mesajele cu transmisie celulară"</string>
-    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situaţiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcţionarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
+    <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Permite aplicației să citească mesajele primite prin transmisie celulară de dispozitivul dvs. Alertele cu transmisie celulară sunt difuzate în unele locații pentru a vă avertiza cu privire la situațiile de urgenţă. Aplicaţiile rău intenţionate pot afecta performanţa sau funcționarea dispozitivului dvs. când este primită o transmisie celulară de urgenţă."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"citire feeduri abonat"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Permite aplicației să obţină detalii despre feedurile sincronizate în prezent."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"trimite și vede mesajele SMS"</string>
-    <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariţia unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"trimită și să vadă mesajele SMS"</string>
+    <string name="permdesc_sendSms" msgid="7094729298204937667">"Permite aplicației să trimită mesaje SMS, ceea ce ar putea determina apariția unor taxe neaşteptate. Aplicaţiile rău intenţionate pot acumula costuri prin trimiterea mesajelor fără confirmarea dvs."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"citeşte mesajele text (SMS sau MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Permite aplicației să citească mesajele SMS stocate pe tabletă sau pe cardul SIM. În acest fel, aplicația poate citi toate mesajele SMS, indiferent de conţinutul sau de gradul de confidenţialitate al acestora."</string>
     <string name="permdesc_readSms" product="tv" msgid="5102425513647038535">"Permite aplicației să citească mesajele SMS stocate pe televizor sau pe cardul SIM. Cu această permisiune, aplicația poate citi toate mesajele SMS, indiferent de conținutul sau de gradul de confidențialitate al acestora."</string>
@@ -292,11 +292,11 @@
     <string name="permlab_killBackgroundProcesses" msgid="3914026687420177202">"închide alte aplicații"</string>
     <string name="permdesc_killBackgroundProcesses" msgid="4593353235959733119">"Permite aplicației să oprească procesele derulate în fundal de alte aplicații. Acest lucru poate face ca respectivele aplicații să nu mai ruleze."</string>
     <string name="permlab_systemAlertWindow" msgid="3543347980839518613">"suprapune elemente vizuale peste alte aplicații"</string>
-    <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părţi ale interfeţei cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeţei în orice aplicație sau pot schimba ceea ce credeţi că vedeţi în alte aplicații."</string>
+    <string name="permdesc_systemAlertWindow" msgid="8584678381972820118">"Permite aplicației să suprapună elemente vizuale peste alte aplicații sau părți ale interfeței cu utilizatorul. Acestea pot interfera cu utilizarea de către dvs. a interfeței în orice aplicație sau pot schimba ceea ce credeți că vedeţi în alte aplicații."</string>
     <string name="permlab_persistentActivity" msgid="8841113627955563938">"rulare continuă a aplicației"</string>
-    <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părţi ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcţionarea tabletei."</string>
+    <string name="permdesc_persistentActivity" product="tablet" msgid="8525189272329086137">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea tabletei."</string>
     <string name="permdesc_persistentActivity" product="tv" msgid="5086862529499103587">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea televizorului."</string>
-    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părţi ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcţionarea telefonului."</string>
+    <string name="permdesc_persistentActivity" product="default" msgid="4384760047508278272">"Permite aplicației să declare persistente în memorie anumite părți ale sale. Acest lucru poate limita memoria disponibilă pentru alte aplicații și poate încetini funcționarea telefonului."</string>
     <string name="permlab_getPackageSize" msgid="7472921768357981986">"măsurare spaţiu de stocare al aplicației"</string>
     <string name="permdesc_getPackageSize" msgid="3921068154420738296">"Permite aplicației să preia dimensiunile codului, ale datelor și ale memoriei cache"</string>
     <string name="permlab_writeSettings" msgid="2226195290955224730">"modifică setări de sistem"</string>
@@ -310,17 +310,17 @@
     <string name="permdesc_broadcastSticky" product="tv" msgid="6839285697565389467">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze televizorul, determinându-l să utilizeze prea multă memorie."</string>
     <string name="permdesc_broadcastSticky" product="default" msgid="2825803764232445091">"Permite aplicației să trimită mesaje difuzate persistente, care se păstrează după terminarea difuzării mesajului. Utilizarea excesivă a acestei funcții poate să încetinească sau să destabilizeze telefonul, determinându-l să utilizeze prea multă memorie."</string>
     <string name="permlab_readContacts" msgid="8348481131899886131">"citeşte agenda"</string>
-    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
+    <string name="permdesc_readContacts" product="tablet" msgid="5294866856941149639">"Permite aplicației să citească datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
     <string name="permdesc_readContacts" product="tv" msgid="1839238344654834087">"Permite aplicației să citească datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane. Cu această permisiune, aplicațiile pot salva datele de contact, iar aplicațiile rău-intenționate pot permite accesul la datele de contact fără cunoștința dvs."</string>
-    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără ştirea dvs."</string>
+    <string name="permdesc_readContacts" product="default" msgid="8440654152457300662">"Permite aplicației să citească datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane. Cu această permisiune aplicația salvează datele dvs. de contact, iar aplicațiile rău intenţionate pot distribui datele de contact fără știrea dvs."</string>
     <string name="permlab_writeContacts" msgid="5107492086416793544">"modifică agenda"</string>
-    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
+    <string name="permdesc_writeContacts" product="tablet" msgid="897243932521953602">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe tabletă, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
     <string name="permdesc_writeContacts" product="tv" msgid="5438230957000018959">"Permite aplicației să modifice datele despre persoanele de contact salvate pe televizor, inclusiv frecvența cu care ați apelat, ați trimis e-mailuri sau ați comunicat în alte moduri cu anumite persoane de contact. Cu această permisiune, aplicația poate șterge datele de contact."</string>
-    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvenţa cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
+    <string name="permdesc_writeContacts" product="default" msgid="589869224625163558">"Permite aplicației să modifice datele despre persoanele din agenda stocată pe telefon, inclusiv frecvența cu care aţi apelat, aţi trimis e-mailuri sau aţi comunicat în alte moduri cu anumite persoane din agendă. Cu această permisiune aplicația poate șterge datele de contact."</string>
     <string name="permlab_readCallLog" msgid="3478133184624102739">"citeşte jurnalul de apeluri"</string>
-    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
+    <string name="permdesc_readCallLog" product="tablet" msgid="3700645184870760285">"Permite aplicației să citească jurnalul de apeluri al tabletei, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
     <string name="permdesc_readCallLog" product="tv" msgid="5611770887047387926">"Permite aplicației să citească jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune, aplicațiile pot să salveze datele din jurnalul de apeluri, iar aplicațiile rău-intenționate pot permite accesul la datele din jurnalul de apeluri fără cunoștința dvs."</string>
-    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără ştirea dvs."</string>
+    <string name="permdesc_readCallLog" product="default" msgid="5777725796813217244">"Permite aplicației să citească jurnalul de apeluri al telefonului, inclusiv datele despre apelurile primite și efectuate. Cu această permisiune aplicația salvează datele dvs. din jurnalul de apeluri, iar aplicațiile rău intenţionate pot distribui aceste date fără știrea dvs."</string>
     <string name="permlab_writeCallLog" msgid="8552045664743499354">"scrie jurnalul de apeluri"</string>
     <string name="permdesc_writeCallLog" product="tablet" msgid="6661806062274119245">"Permite aplicației să modifice jurnalul de apeluri al tabletei dvs., inclusiv datele despre apelurile primite sau efectuate. Aplicaţiile rău intenţionate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul dvs. de apeluri."</string>
     <string name="permdesc_writeCallLog" product="tv" msgid="4225034892248398019">"Permite aplicației să modifice jurnalul de apeluri al televizorului, inclusiv datele despre apelurile primite sau efectuate. Aplicațiile rău-intenționate pot utiliza această permisiune pentru a șterge sau pentru a modifica jurnalul de apeluri."</string>
@@ -331,10 +331,10 @@
     <string name="permdesc_readCalendar" product="tablet" msgid="4216462049057658723">"Permite aplicației să citească toate evenimentele din calendar stocate pe tabletă, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
     <string name="permdesc_readCalendar" product="tv" msgid="3191352452242394196">"Permite aplicației să citească toate evenimentele din calendar stocate pe televizor, inclusiv cele ale prietenilor sau colegilor. Cu această permisiune, aplicația poate să permită accesul la datele din calendar sau să le salveze, indiferent dacă acestea sunt confidențiale sau sensibile."</string>
     <string name="permdesc_readCalendar" product="default" msgid="7434548682470851583">"Permite aplicației să citească toate evenimentele din calendar stocate pe telefon, inclusiv cele ale prietenilor sau colegilor. Acest lucru poate permite aplicației să distribuie sau să salveze datele din calendar, indiferent dacă acestea sunt confidenţiale sau sensibile."</string>
-    <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaţilor fără ştirea proprietarului"</string>
-    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
+    <string name="permlab_writeCalendar" msgid="8438874755193825647">"adăugarea sau modificarea evenimentelor din calendar și trimiterea de e-mailuri invitaților fără știrea proprietarului"</string>
+    <string name="permdesc_writeCalendar" product="tablet" msgid="6679035520113668528">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe tabletă, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string>
     <string name="permdesc_writeCalendar" product="tv" msgid="1273290605500902507">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe televizor, inclusiv pe cele ale prietenilor sau ale colegilor. Cu această permisiune, aplicația poate să trimită mesaje care par că vin din partea proprietarilor calendarului sau să modifice evenimentele fără cunoștința acestora."</string>
-    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără ştirea proprietarilor."</string>
+    <string name="permdesc_writeCalendar" product="default" msgid="2324469496327249376">"Permite aplicației să adauge, să elimine și să modifice evenimentele pe care le puteți modifica pe telefon, inclusiv cele ale prietenilor sau colegilor dvs. În acest fel, aplicația poate trimite mesaje care par să vină de la proprietarii calendarelor sau să modifice evenimentele fără știrea proprietarilor."</string>
     <string name="permlab_accessLocationExtraCommands" msgid="2836308076720553837">"accesare comenzi suplimentare ale furnizorului locației"</string>
     <string name="permdesc_accessLocationExtraCommands" msgid="6078307221056649927">"Permite aplicației să acceseze comenzi suplimentare pentru furnizorul locației. Aplicația ar putea să utilizeze această permisiune pentru a influența operațiile GPS sau ale altor surse de locații."</string>
     <string name="permlab_accessFineLocation" msgid="1191898061965273372">"locaţia exactă (bazată pe rețea și GPS)"</string>
@@ -343,7 +343,7 @@
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Permite aplicației să obţină locaţia dvs. aproximativă. Această locație este dedusă de serviciile de localizare utilizând surse de localizare prin rețele, cum ar fi cele prin turn de celule și Wi-Fi. Pentru a fi utilizate de aplicație, aceste servicii de localizare trebuie să fie activate și disponibile pe dispozitivul dvs. Aplicaţiile pot utiliza această permisiune pentru a determina locaţia dvs. aproximativă."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"modificare setări audio"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Permite aplicației să modifice setările audio globale, cum ar fi volumul și difuzorul care este utilizat pentru ieșire."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistrare audio"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"înregistreze sunet"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Permite aplicației să efectueze înregistrări audio cu ajutorul microfonului. Cu această permisiune aplicația efectuează oricând înregistrări audio fără confirmare."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"comunicare cu cardul SIM"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Permite aplicației să trimită comenzi pe cardul SIM. Această permisiune este foarte periculoasă."</string>
@@ -354,11 +354,11 @@
     <string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string>
     <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
-    <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariţia unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
+    <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
     <string name="permdesc_accessImsCallService" msgid="8992884015198298775">"Permite aplicației să folosească serviciul IMS pentru apeluri, fără intervenția dvs."</string>
     <string name="permlab_readPhoneState" msgid="9178228524507610486">"citeşte starea și identitatea telefonului"</string>
-    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicația stabileşte numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanţă conectat printr-un apel."</string>
+    <string name="permdesc_readPhoneState" msgid="1639212771826125528">"Permite aplicației să acceseze funcţiile de telefon ale dispozitivului. Cu această permisiune aplicația stabilește numărul de telefon și ID-urile de dispozitiv, dacă un apel este activ, precum și numărul de la distanţă conectat printr-un apel."</string>
     <string name="permlab_wakeLock" product="tablet" msgid="1531731435011495015">"împiedicarea computerului tablet PC să intre în repaus"</string>
     <string name="permlab_wakeLock" product="tv" msgid="2601193288949154131">"împiedică intrarea televizorului în stare de inactivitate"</string>
     <string name="permlab_wakeLock" product="default" msgid="573480187941496130">"împiedicare intrare telefon în repaus"</string>
@@ -756,7 +756,7 @@
     <string name="js_dialog_before_unload_negative_button" msgid="5614861293026099715">"Rămâneți în această pagină"</string>
     <string name="js_dialog_before_unload" msgid="3468816357095378590">"<xliff:g id="MESSAGE">%s</xliff:g>\n\nSigur doriți să părăsiți această pagină?"</string>
     <string name="save_password_label" msgid="6860261758665825069">"Confirmați"</string>
-    <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriţi și micşoraţi prin dublă atingere."</string>
+    <string name="double_tap_toast" msgid="4595046515400268881">"Sfat: măriți și micșorați prin dublă atingere."</string>
     <string name="autofill_this_form" msgid="4616758841157816676">"Automat"</string>
     <string name="setup_autofill" msgid="7103495070180590814">"Conf.Compl.auto."</string>
     <string name="autofill_address_name_separator" msgid="6350145154779706772">" "</string>
@@ -767,7 +767,7 @@
     <string name="autofill_postal_code" msgid="4696430407689377108">"Cod poştal"</string>
     <string name="autofill_state" msgid="6988894195520044613">"Stat"</string>
     <string name="autofill_zip_code" msgid="8697544592627322946">"Cod ZIP"</string>
-    <string name="autofill_county" msgid="237073771020362891">"Judeţ"</string>
+    <string name="autofill_county" msgid="237073771020362891">"Județ"</string>
     <string name="autofill_island" msgid="4020100875984667025">"Insulă"</string>
     <string name="autofill_district" msgid="8400735073392267672">"District"</string>
     <string name="autofill_department" msgid="5343279462564453309">"Departament"</string>
@@ -776,11 +776,11 @@
     <string name="autofill_area" msgid="3547409050889952423">"Zonă"</string>
     <string name="autofill_emirate" msgid="2893880978835698818">"Emirat"</string>
     <string name="permlab_readHistoryBookmarks" msgid="3775265775405106983">"citeşte marcajele și istoricul web"</string>
-    <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+    <string name="permdesc_readHistoryBookmarks" msgid="8462378226600439658">"Permite aplicației să citească istoricul tuturor adreselor URL accesate de Browser și toate marcajele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
     <string name="permlab_writeHistoryBookmarks" msgid="3714785165273314490">"scrie în marcajele și în istoricul web"</string>
-    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="tablet" msgid="6825527469145760922">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe tabletă. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
     <string name="permdesc_writeHistoryBookmarks" product="tv" msgid="7007393823197766548">"Permite aplicației să modifice istoricul sau marcajele browserului stocate pe televizor. Cu această permisiune, aplicația poate șterge sau modifica datele din browser. Notă: această permisiune nu poate fi aplicată de browsere terță parte sau de alte aplicații cu capacități de navigare pe web."</string>
-    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacităţi de navigare pe web."</string>
+    <string name="permdesc_writeHistoryBookmarks" product="default" msgid="8497389531014185509">"Permite aplicației să modifice istoricul Browserului sau marcajele stocate pe telefon. În acest fel, aplicația poate șterge sau modifica datele din Browser. Notă: această permisiune nu poate fi aplicată de browsere terţă parte sau de alte aplicații cu capacități de navigare pe web."</string>
     <string name="permlab_setAlarm" msgid="1379294556362091814">"setează o alarmă"</string>
     <string name="permdesc_setAlarm" msgid="316392039157473848">"Permite aplicației să seteze o alarmă într-o aplicație de ceas cu alarmă instalată. Este posibil ca unele aplicații de ceas cu alarmă să nu implementeze această funcție."</string>
     <string name="permlab_addVoicemail" msgid="5525660026090959044">"adăugare mesagerie vocală"</string>
@@ -803,11 +803,11 @@
     <string name="searchview_description_search" msgid="6749826639098512120">"Căutați"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"Interogare de căutare"</string>
     <string name="searchview_description_clear" msgid="1330281990951833033">"Ștergeți interogarea"</string>
-    <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteţi interogarea"</string>
+    <string name="searchview_description_submit" msgid="2688450133297983542">"Trimiteți interogarea"</string>
     <string name="searchview_description_voice" msgid="2453203695674994440">"Căutare vocală"</string>
-    <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Exploraţi prin atingere?"</string>
-    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
-    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Exploraţi prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
+    <string name="enable_explore_by_touch_warning_title" msgid="7460694070309730149">"Activați Explorați prin atingere?"</string>
+    <string name="enable_explore_by_touch_warning_message" product="tablet" msgid="8655887539089910577">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu tableta."</string>
+    <string name="enable_explore_by_touch_warning_message" product="default" msgid="2708199672852373195">"<xliff:g id="ACCESSIBILITY_SERVICE_NAME">%1$s</xliff:g> doreşte să activeze funcţia Explorați prin atingere. Când această funcție este activată, puteți auzi sau vedea descrieri pentru ceea ce se află sub degetul dvs. sau puteți efectua gesturi pentru a interacţiona cu telefonul."</string>
     <string name="oneMonthDurationPast" msgid="7396384508953779925">"cu 1 lună în urmă"</string>
     <string name="beforeOneMonthDurationPast" msgid="909134546836499826">"Cu mai mult de 1 lună în urmă"</string>
     <plurals name="last_num_days" formatted="false" msgid="5104533550723932025">
@@ -918,7 +918,7 @@
     <string name="launch_warning_original" msgid="188102023021668683">"<xliff:g id="APP_NAME">%1$s</xliff:g> a fost lansată iniţial."</string>
     <string name="screen_compat_mode_scale" msgid="3202955667675944499">"Scară"</string>
     <string name="screen_compat_mode_show" msgid="4013878876486655892">"Afişaţi întotdeauna"</string>
-    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivaţi acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
+    <string name="screen_compat_mode_hint" msgid="1064524084543304459">"Reactivați acest mod din Setări de sistem &gt; Aplicații &gt; Descărcate."</string>
     <string name="smv_application" msgid="3307209192155442829">"Aplicaţia <xliff:g id="APPLICATION">%1$s</xliff:g> (procesul <xliff:g id="PROCESS">%2$s</xliff:g>) a încălcat propria politică StrictMode."</string>
     <string name="smv_process" msgid="5120397012047462446">"Procesul <xliff:g id="PROCESS">%1$s</xliff:g> a încălcat propria politică StrictMode."</string>
     <string name="android_upgrading_title" msgid="1584192285441405746">"Android trece la o versiune superioară..."</string>
@@ -1002,10 +1002,10 @@
     <string name="sms_control_message" msgid="3867899169651496433">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; trimite un număr mare de mesaje SMS. Permiteți acestei aplicații să trimită în continuare mesaje?"</string>
     <string name="sms_control_yes" msgid="3663725993855816807">"Permiteți"</string>
     <string name="sms_control_no" msgid="625438561395534982">"Refuzaţi"</string>
-    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; intenţionează să trimită un mesaj la &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
+    <string name="sms_short_code_confirm_message" msgid="1645436466285310855">"&lt;b&gt;<xliff:g id="APP_NAME">%1$s</xliff:g>&lt;/b&gt; intenționează să trimită un mesaj la &lt;b&gt;<xliff:g id="DEST_ADDRESS">%2$s</xliff:g>&lt;/b&gt;."</string>
     <string name="sms_short_code_details" msgid="5873295990846059400">"Acest lucru "<b>"poate genera costuri"</b>" în contul dvs. mobil."</string>
     <string name="sms_premium_short_code_details" msgid="7869234868023975"><b>"Acest lucru va genera costuri în contul dvs. mobil."</b></string>
-    <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteţi"</string>
+    <string name="sms_short_code_confirm_allow" msgid="4458878637111023413">"Trimiteți"</string>
     <string name="sms_short_code_confirm_deny" msgid="2927389840209170706">"Anulați"</string>
     <string name="sms_short_code_remember_choice" msgid="5289538592272218136">"Doresc să se reţină opţiunea"</string>
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puteți modifica ulterior în Setări &gt; Aplicații"</string>
@@ -1080,8 +1080,8 @@
     <string name="ext_media_status_formatting" msgid="1085079556538644861">"Se formatează…"</string>
     <string name="ext_media_status_missing" msgid="5638633895221670766">"Nu este introdus"</string>
     <string name="activity_list_empty" msgid="1675388330786841066">"Nu s-a găsit nicio activitate potrivită."</string>
-    <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcţionează rezultatele media"</string>
-    <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcţioneze rezultate media către alte dispozitive externe."</string>
+    <string name="permlab_route_media_output" msgid="1642024455750414694">"Direcționează rezultatele media"</string>
+    <string name="permdesc_route_media_output" msgid="4932818749547244346">"Permite unei aplicații să direcționeze rezultate media către alte dispozitive externe."</string>
     <string name="permlab_readInstallSessions" msgid="6165432407628065939">"Citirea sesiunilor de instalare"</string>
     <string name="permdesc_readInstallSessions" msgid="2049771699626019849">"Permite unei aplicații accesul la citirea sesiunilor de instalare. Aceasta poate vedea detalii despre instalările de pachete active."</string>
     <string name="permlab_requestInstallPackages" msgid="1772330282283082214">"Solicită instalarea pachetelor"</string>
@@ -1124,7 +1124,7 @@
     <string name="upload_file" msgid="2897957172366730416">"Alegeţi un fişier"</string>
     <string name="no_file_chosen" msgid="6363648562170759465">"Nu au fost găsite fișiere"</string>
     <string name="reset" msgid="2448168080964209908">"Resetaţi"</string>
-    <string name="submit" msgid="1602335572089911941">"Trimiteţi"</string>
+    <string name="submit" msgid="1602335572089911941">"Trimiteți"</string>
     <string name="car_mode_disable_notification_title" msgid="3164768212003864316">"Mod Maşină activat"</string>
     <string name="car_mode_disable_notification_message" msgid="8035230537563503262">"Atingeți pentru a ieşi din modul Maşină."</string>
     <string name="tethered_notification_title" msgid="3146694234398202601">"Tethering sau hotspot activ"</string>
@@ -1160,21 +1160,21 @@
     <string name="choose_account_label" msgid="5655203089746423927">"Alegeţi un cont"</string>
     <string name="add_account_label" msgid="2935267344849993553">"Adăugaţi un cont"</string>
     <string name="add_account_button_label" msgid="3611982894853435874">"Adăugaţi un cont"</string>
-    <string name="number_picker_increment_button" msgid="2412072272832284313">"Creşteţi"</string>
+    <string name="number_picker_increment_button" msgid="2412072272832284313">"Creșteți"</string>
     <string name="number_picker_decrement_button" msgid="476050778386779067">"Reduceţi"</string>
     <string name="number_picker_increment_scroll_mode" msgid="3073101067441638428">"Atingeți și țineți apăsat <xliff:g id="VALUE">%s</xliff:g>."</string>
     <string name="number_picker_increment_scroll_action" msgid="9101473045891835490">"Glisaţi în sus pentru a creşte și în jos pentru a reduce."</string>
-    <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creşteţi valoarea pentru minute"</string>
+    <string name="time_picker_increment_minute_button" msgid="8865885114028614321">"Creșteți valoarea pentru minute"</string>
     <string name="time_picker_decrement_minute_button" msgid="6246834937080684791">"Reduceţi valoarea pentru minute"</string>
-    <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creşteţi valoarea pentru oră"</string>
+    <string name="time_picker_increment_hour_button" msgid="3652056055810223139">"Creșteți valoarea pentru oră"</string>
     <string name="time_picker_decrement_hour_button" msgid="1377479863429214792">"Reduceţi valoarea pentru oră"</string>
     <string name="time_picker_increment_set_pm_button" msgid="4147590696151230863">"Setaţi valoarea PM"</string>
     <string name="time_picker_decrement_set_am_button" msgid="8302140353539486752">"Setaţi valoarea AM"</string>
-    <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creşteţi valoarea pentru lună"</string>
+    <string name="date_picker_increment_month_button" msgid="5369998479067934110">"Creșteți valoarea pentru lună"</string>
     <string name="date_picker_decrement_month_button" msgid="1832698995541726019">"Reduceţi valoarea pentru lună"</string>
-    <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creşteţi valoarea pentru zi"</string>
+    <string name="date_picker_increment_day_button" msgid="7130465412308173903">"Creșteți valoarea pentru zi"</string>
     <string name="date_picker_decrement_day_button" msgid="4131881521818750031">"Reduceţi valoarea pentru zi"</string>
-    <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creşteţi valoarea pentru an"</string>
+    <string name="date_picker_increment_year_button" msgid="6318697384310808899">"Creșteți valoarea pentru an"</string>
     <string name="date_picker_decrement_year_button" msgid="4482021813491121717">"Reduceţi valoarea pentru an"</string>
     <string name="date_picker_prev_month_button" msgid="2858244643992056505">"Luna trecută"</string>
     <string name="date_picker_next_month_button" msgid="5559507736887605055">"Luna viitoare"</string>
@@ -1245,7 +1245,7 @@
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Tabletă"</string>
     <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Telefon"</string>
-    <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căşti"</string>
+    <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Căști"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Difuz. dispozit. andocare"</string>
     <string name="default_media_route_name_hdmi" msgid="2450970399023478055">"HDMI"</string>
     <string name="default_audio_route_category_name" msgid="3722811174003886946">"Sistem"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index f1deb22..0621bbe 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -915,7 +915,7 @@
     <string name="anr_application_process" msgid="8941757607340481057">"Приложение \"<xliff:g id="APPLICATION">%1$s</xliff:g>\" не отвечает. Закрыть его?"</string>
     <string name="anr_process" msgid="6513209874880517125">"Приложение \"<xliff:g id="PROCESS">%1$s</xliff:g>\" не отвечает.\n\nЗакрыть его?"</string>
     <string name="force_close" msgid="8346072094521265605">"ОК"</string>
-    <string name="report" msgid="4060218260984795706">"Отзыв"</string>
+    <string name="report" msgid="4060218260984795706">"Отправить отчет"</string>
     <string name="wait" msgid="7147118217226317732">"Подождать"</string>
     <string name="webpage_unresponsive" msgid="3272758351138122503">"Страница не отвечает.\n\nЗакрыть ее?"</string>
     <string name="launch_warning_title" msgid="1547997780506713581">"Приложение перенаправлено"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index d5bafd25..582f912 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -229,7 +229,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"සම්බන්ධතා"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ඔබේ සම්බන්ධතාවලට පිවිසෙන්න"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"ස්ථානය"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානය ප්‍රවේශ කිරීම"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"මෙම උපාංගයේ ස්ථානයට ප්‍රවේශ කරන්න"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"දින දර්ශනය"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"ඔබේ දින දර්ශනයට පිවිසෙන්න"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"කෙටි පණිවිඩ"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index cf87e2a6..c5ca3c2 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -993,7 +993,7 @@
     <string name="wifi_p2p_failed_message" msgid="3763669677935623084">"Wi-Fi Direct ni bilo mogoče zagnati."</string>
     <string name="wifi_p2p_enabled_notification_title" msgid="2068321881673734886">"Wi-Fi Direct je vklopljen"</string>
     <string name="wifi_p2p_enabled_notification_message" msgid="1638949953993894335">"Dotaknite se za nastavitve"</string>
-    <string name="accept" msgid="1645267259272829559">"Sprejmi"</string>
+    <string name="accept" msgid="1645267259272829559">"Sprejmem"</string>
     <string name="decline" msgid="2112225451706137894">"Zavrni"</string>
     <string name="wifi_p2p_invitation_sent_title" msgid="1318975185112070734">"Povabilo je poslano"</string>
     <string name="wifi_p2p_invitation_to_connect_title" msgid="4958803948658533637">"Povabilo za povezavo"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 86f9d11..7df0f86 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -229,7 +229,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Kontaktet"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"qasu te kontaktet e tua"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Vendndodhja"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"qasu te vendndodhja e kësaj pajisjeje"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"qasjen te vendndodhja e kësaj pajisjeje"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalendari"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"qasu te kalendari yt"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index a3a4b32..5bb2d78 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -230,21 +230,21 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Контакти"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"приступи контактима"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Локација"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"приступ локацији овог уређаја"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"приступи локацији овог уређаја"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Календар"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"приступи календару"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"шаље и прегледа SMS поруке"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Складиште"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"приступи сликама, медијима и датотекама на уређају"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"приступа сликама, медијима и датотекама на уређају"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Микрофон"</string>
-    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снимање аудио снимака"</string>
+    <string name="permgroupdesc_microphone" msgid="4988812113943554584">"снима аудио снимке"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Камера"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снимање слика и видео снимака"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"снима слике и видео снимке"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Телефон"</string>
-    <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућивање телефонских позива и управљање њима"</string>
+    <string name="permgroupdesc_phone" msgid="6234224354060641055">"упућује телефонске позиве и управља њима"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Сензори за тело"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступ подацима сензора о виталним функцијама"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"приступа подацима сензора о виталним функцијама"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Преузима садржај прозора"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Проверава садржај прозора са којим остварујете интеракцију."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Укључи Истраживања додиром"</string>
@@ -273,7 +273,7 @@
     <string name="permdesc_readCellBroadcasts" msgid="6361972776080458979">"Омогућава апликацији да чита поруке инфо сервиса које уређај прима. Упозорења инфо сервиса се на неким локацијама примају као упозорења на хитне случајеве. Злонамерне апликације могу да утичу на учинак или ометају функционисање уређаја када се прими порука инфо сервиса о хитном случају."</string>
     <string name="permlab_subscribedFeedsRead" msgid="4756609637053353318">"читање пријављених фидова"</string>
     <string name="permdesc_subscribedFeedsRead" msgid="5557058907906144505">"Дозвољава апликацији да преузима детаље о тренутно синхронизованим фидовима."</string>
-    <string name="permlab_sendSms" msgid="7544599214260982981">"шаљи и прегледај SMS поруке"</string>
+    <string name="permlab_sendSms" msgid="7544599214260982981">"шаље и прегледа SMS поруке"</string>
     <string name="permdesc_sendSms" msgid="7094729298204937667">"Дозвољава апликацији да шаље SMS поруке. Ово може да доведе до неочекиваних трошкова. Злонамерне апликације могу да шаљу поруке без ваше потврде, што може да изазове трошкове."</string>
     <string name="permlab_readSms" msgid="8745086572213270480">"читање текстуалних порука (SMS или MMS)"</string>
     <string name="permdesc_readSms" product="tablet" msgid="2467981548684735522">"Дозвољава апликацији да чита SMS поруке ускладиштене на таблету или SIM картици. Ово омогућава апликацији да чита све SMS поруке, без обзира на садржај или поверљивост."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 237afe7..29fd6a1 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -853,7 +853,7 @@
     <string name="Midnight" msgid="5630806906897892201">"Midnatt"</string>
     <string name="elapsed_time_short_format_mm_ss" msgid="4431555943828711473">"<xliff:g id="MINUTES">%1$02d</xliff:g>:<xliff:g id="SECONDS">%2$02d</xliff:g>"</string>
     <string name="elapsed_time_short_format_h_mm_ss" msgid="1846071997616654124">"<xliff:g id="HOURS">%1$d</xliff:g>:<xliff:g id="MINUTES">%2$02d</xliff:g>:<xliff:g id="SECONDS">%3$02d</xliff:g>"</string>
-    <string name="selectAll" msgid="6876518925844129331">"Välj alla"</string>
+    <string name="selectAll" msgid="6876518925844129331">"Markera allt"</string>
     <string name="cut" msgid="3092569408438626261">"Klipp ut"</string>
     <string name="copy" msgid="2681946229533511987">"Kopiera"</string>
     <string name="paste" msgid="5629880836805036433">"Klistra in"</string>
@@ -1190,7 +1190,7 @@
     <string name="action_menu_overflow_description" msgid="2295659037509008453">"Fler alternativ"</string>
     <string name="action_bar_home_description_format" msgid="7965984360903693903">"%1$s, %2$s"</string>
     <string name="action_bar_home_subtitle_description_format" msgid="6985546530471780727">"%1$s, %2$s, %3$s"</string>
-    <string name="storage_internal" msgid="4891916833657929263">"Internminne"</string>
+    <string name="storage_internal" msgid="4891916833657929263">"lagring"</string>
     <string name="storage_sd_card" msgid="3282948861378286745">"SD-kort"</string>
     <string name="storage_sd_card_label" msgid="6347111320774379257">"SD-kort (<xliff:g id="MANUFACTURER">%s</xliff:g>)"</string>
     <string name="storage_usb_drive" msgid="6261899683292244209">"USB-enhet"</string>
@@ -1235,7 +1235,7 @@
     <string name="activity_resolver_use_once" msgid="2404644797149173758">"Bara en gång"</string>
     <string name="activity_resolver_work_profiles_support" msgid="185598180676883455">"%1$s har inte stöd för arbetsprofil"</string>
     <string name="default_audio_route_name" product="tablet" msgid="4617053898167127471">"Surfplatta"</string>
-    <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"Tv"</string>
+    <string name="default_audio_route_name" product="tv" msgid="9158088547603019321">"TV"</string>
     <string name="default_audio_route_name" product="default" msgid="4239291273420140123">"Mobil"</string>
     <string name="default_audio_route_name_headphones" msgid="8119971843803439110">"Hörlurar"</string>
     <string name="default_audio_route_name_dock_speakers" msgid="6240602982276591864">"Dockningsstationens högtalare"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 6445f6a..d367887 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -231,7 +231,7 @@
     <string name="permgrouplab_contacts" msgid="3657758145679177612">"Anwani"</string>
     <string name="permgroupdesc_contacts" msgid="6951499528303668046">"ifikie anwani zako"</string>
     <string name="permgrouplab_location" msgid="7275582855722310164">"Mahali"</string>
-    <string name="permgroupdesc_location" msgid="1346617465127855033">"fikia mahali kilipo kifaa hiki"</string>
+    <string name="permgroupdesc_location" msgid="1346617465127855033">"ifikie mahali kilipo kifaa hiki"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Kalenda"</string>
     <string name="permgroupdesc_calendar" msgid="3889615280211184106">"fikia kalenda yako"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
diff --git a/core/res/res/values-uz-rUZ-watch/strings.xml b/core/res/res/values-uz-rUZ-watch/strings.xml
index 0fe54a1..44af51d 100644
--- a/core/res/res/values-uz-rUZ-watch/strings.xml
+++ b/core/res/res/values-uz-rUZ-watch/strings.xml
@@ -22,15 +22,15 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="android_upgrading_apk" msgid="1090732262010398759">"<xliff:g id="NUMBER_1">%2$d</xliff:g>dan <xliff:g id="NUMBER_0">%1$d</xliff:g> ilova."</string>
     <string name="permgrouplab_sensors" msgid="202675452368612754">"Sensorlar"</string>
-    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirishga ruxsat berish"</string>
+    <string name="permgrouplab_contactswear" msgid="2340286500790908344">"kontaktlarga kirish"</string>
     <string name="permgrouplab_locationwear" msgid="6275317222482780209">"mazkur soatning joylashgan joyini ko‘rishga ruxsat berish"</string>
     <string name="permgrouplab_calendarwear" msgid="441900844045065081">"taqvim ma’lumotlariga kirish"</string>
     <string name="permgrouplab_smswear" msgid="6849506550342974220">"SMS xabarlarni yuborish va ko‘rish"</string>
     <string name="permgrouplab_storagewear" msgid="1003807594193602313">"Soatingizdagi rasmlar, media va fayllarga kirish"</string>
     <string name="permgrouplab_microphonewear" msgid="1047561180980891136">"ovoz yozib olish"</string>
-    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"rasmga tushirish va videoga olish"</string>
+    <string name="permgrouplab_camerawear" msgid="4543951283103407017">"suratga olish va video yozib olish"</string>
     <string name="permgrouplab_phonewear" msgid="134365036753766126">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string>
-    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"asosiy belgilaringiz haqidagi sezgich ma’lumotlaridan foydalanishga ruxsat"</string>
+    <string name="permgrouplab_sensorswear" msgid="1429324744329327663">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string>
     <string name="permlab_statusBarServicewear" msgid="2469402818964691034">"holat qatorida ko‘rinishi"</string>
     <string name="permlab_bodySensorswear" msgid="7857941041202791873">"tana sezgichlari (m-n, yurak urishi sensori) ma’lumotlaridan foydalanishga ruxsat"</string>
     <string name="permlab_accessFineLocationwear" msgid="5584423486924377563">"aniq joylashuv (GPS va tarmoqqa asoslanib) ma’lumotlaridan foydalanishga ruxsat"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 325ad91..b7ae992 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -231,19 +231,19 @@
     <string name="permgrouplab_location" msgid="7275582855722310164">"Joylashuv"</string>
     <string name="permgroupdesc_location" msgid="1346617465127855033">"qurilmaning joylashuvi haqidagi ma’lumotlarga kirish"</string>
     <string name="permgrouplab_calendar" msgid="5863508437783683902">"Taqvim"</string>
-    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvimga kirish"</string>
+    <string name="permgroupdesc_calendar" msgid="3889615280211184106">"taqvim ma’lumotlariga kirish"</string>
     <string name="permgrouplab_sms" msgid="228308803364967808">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="4656988620100940350">"SMS xabarlarni yuborish va ko‘rish"</string>
     <string name="permgrouplab_storage" msgid="1971118770546336966">"Xotira"</string>
-    <string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi rasm, media va fayllarga kirish"</string>
+    <string name="permgroupdesc_storage" msgid="637758554581589203">"qurilmangizdagi rasm, multimedia va fayllarga kirish"</string>
     <string name="permgrouplab_microphone" msgid="171539900250043464">"Mikrofon"</string>
     <string name="permgroupdesc_microphone" msgid="4988812113943554584">"ovoz yozib olish"</string>
     <string name="permgrouplab_camera" msgid="4820372495894586615">"Kamera"</string>
-    <string name="permgroupdesc_camera" msgid="3250611594678347720">"rasm va videoga olish"</string>
+    <string name="permgroupdesc_camera" msgid="3250611594678347720">"suratga olish va video yozib olish"</string>
     <string name="permgrouplab_phone" msgid="5229115638567440675">"Telefon"</string>
     <string name="permgroupdesc_phone" msgid="6234224354060641055">"telefon qo‘ng‘iroqlarini amalga oshirish va boshqarish"</string>
     <string name="permgrouplab_sensors" msgid="416037179223226722">"Tana sezgichlari"</string>
-    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"asosiy belgilaringiz haqidagi sezgich ma’lumotlariga kirish"</string>
+    <string name="permgroupdesc_sensors" msgid="7147968539346634043">"organizm holati haqidagi sezgich ma’lumotlariga kirish"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="3901717936930170320">"Oynadagi kontentni o‘qiydi"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="3772225008605310672">"Joriy oynadagi kontent mazmunini aniqlaydi."</string>
     <string name="capability_title_canRequestTouchExploration" msgid="3108723364676667320">"Teginib o‘rganish xizmatini yoqadi"</string>
@@ -342,7 +342,7 @@
     <string name="permdesc_accessCoarseLocation" msgid="2538200184373302295">"Ilovaga sizning taxminiy joylashuvingizni topishga ruxsat beradi. Ushbu joylashuv Wi-Fi va uyali tarmoq antennalari kabi tarmoq joylashuv manbalaridan foydlanuvchi joylashuv xizmatlari orqali aniqlanadi. Ushbu joylashuv xizmatlari yoqib qo‘yilgan bo‘lishi va qurilmangizdagi ilovaga ulardan foydalanish uchun mavjud bo‘lishi kerak. Ilovalar bundan foydalanib, sizning taxminiy joylashuvingizni aniqlaydi."</string>
     <string name="permlab_modifyAudioSettings" msgid="6095859937069146086">"audio sozlamalaringizni o‘zgartirish"</string>
     <string name="permdesc_modifyAudioSettings" msgid="3522565366806248517">"Ilovalarga tovush va ovoz chiqarish uchun foydalaniladigan karnay kabi global audio sozlamalarini o‘zgartirish uchun ruxsat beradi."</string>
-    <string name="permlab_recordAudio" msgid="3876049771427466323">"audioni yozib olish"</string>
+    <string name="permlab_recordAudio" msgid="3876049771427466323">"ovoz yozib olish"</string>
     <string name="permdesc_recordAudio" msgid="4906839301087980680">"Ilovaga mikrofon yordamida audio yozish uchun ruxsat beradi. Bu huquq ilovaga ruxsatingizsiz audio fayllarni yozib olishga ruxsat beradi."</string>
     <string name="permlab_sim_communication" msgid="1180265879464893029">"sim orqali ulanish"</string>
     <string name="permdesc_sim_communication" msgid="5725159654279639498">"Dasturga SIM kartaga buyruqlar jo‘natishga ruxsat beradi. Bu juda ham xavfli."</string>
@@ -797,9 +797,9 @@
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"space"</string>
     <string name="menu_enter_shortcut_label" msgid="2743362785111309668">"enter"</string>
     <string name="menu_delete_shortcut_label" msgid="3658178007202748164">"delete"</string>
-    <string name="search_go" msgid="8298016669822141719">"Izlash"</string>
+    <string name="search_go" msgid="8298016669822141719">"Qidirish"</string>
     <string name="search_hint" msgid="1733947260773056054">"Qidirish…"</string>
-    <string name="searchview_description_search" msgid="6749826639098512120">"Izlash"</string>
+    <string name="searchview_description_search" msgid="6749826639098512120">"Qidirish"</string>
     <string name="searchview_description_query" msgid="5911778593125355124">"Qidiruv so‘rovi"</string>
     <string name="searchview_description_clear" msgid="1330281990951833033">"So‘rovni tozalash"</string>
     <string name="searchview_description_submit" msgid="2688450133297983542">"So‘rov yaratish"</string>
@@ -1082,7 +1082,7 @@
     <string name="tutorial_double_tap_to_zoom_message_short" msgid="4070433208160063538">"Masshtabni o‘zgartirish uchun ikki marta bosing"</string>
     <string name="gadget_host_error_inflating" msgid="4882004314906466162">"Vidjet qo‘shilmadi."</string>
     <string name="ime_action_go" msgid="8320845651737369027">"O‘tish"</string>
-    <string name="ime_action_search" msgid="658110271822807811">"Izlash"</string>
+    <string name="ime_action_search" msgid="658110271822807811">"Qidirish"</string>
     <string name="ime_action_send" msgid="2316166556349314424">"Jo‘natish"</string>
     <string name="ime_action_next" msgid="3138843904009813834">"Keyingi"</string>
     <string name="ime_action_done" msgid="8971516117910934605">"Tayyor"</string>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 41b05ea..919519e 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -54,4 +54,7 @@
 
     <!-- Do not show the message saying USB is connected in charging mode. -->
     <bool name="config_usbChargingMessage">false</bool>
+
+    <!-- Use a custom transition for RemoteViews. -->
+    <bool name="config_overrideRemoteViewsActivityTransition">true</bool>
 </resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index dc96df4..a6eb68b 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -162,6 +162,9 @@
         <!-- Text color, typeface, size, and style for small text inside of a popup menu. -->
         <attr name="textAppearanceSmallPopupMenu" format="reference" />
 
+        <!-- Text color, typeface, size, and style for header text inside of a popup menu. -->
+        <attr name="textAppearancePopupMenuHeader" format="reference" />
+
         <!-- The underline color and thickness for easy correct suggestion -->
         <attr name="textAppearanceEasyCorrectSuggestion" format="reference" />
 
@@ -729,6 +732,8 @@
         <attr name="listPopupWindowStyle" format="reference" />
         <!-- Default PopupMenu style. -->
         <attr name="popupMenuStyle" format="reference" />
+        <!-- Default context menu PopupMenu style. -->
+        <attr name="contextPopupMenuStyle" format="reference" />
         <!-- Default StackView style. -->
         <attr name="stackViewStyle" format="reference" />
 
@@ -2150,6 +2155,13 @@
               (which is exiting the screen).  The wallpaper remains
               static behind the animation. -->
         <attr name="wallpaperIntraCloseExitAnimation" format="reference" />
+
+        <!--  When opening a new activity from a RemoteViews, this is the
+              animation that is run on the next activity (which is entering the
+              screen). Requires config_overrideRemoteViewsActivityTransition to
+              be true. -->
+        <attr name="activityOpenRemoteViewsEnterAnimation" format="reference" />
+
     </declare-styleable>
 
     <!-- ============================= -->
diff --git a/core/res/res/values/colors_holo.xml b/core/res/res/values/colors_holo.xml
index c29fec6..9d1dda5 100644
--- a/core/res/res/values/colors_holo.xml
+++ b/core/res/res/values/colors_holo.xml
@@ -79,8 +79,7 @@
     <eat-comment />
 
     <color name="holo_primary_dark">#ff000000</color>
-    <color name="holo_primary">#ffe6e6e6</color>
-    <color name="holo_primary_light">#ffffffff</color>
+    <color name="holo_primary">#ff222222</color>
     <color name="holo_control_activated">@color/holo_blue_light</color>
     <color name="holo_control_normal">#39cccccc</color>
     <color name="holo_button_pressed">#59f0f0f0</color>
@@ -88,8 +87,7 @@
 
     <color name="holo_light_primary_dark">#ff000000</color>
     <color name="holo_light_primary">#ffe6e6e6</color>
-    <color name="holo_light_primary_light">#ffffffff</color>
-    <color name="holo_light_control_activated">@color/holo_control_activated</color>
+    <color name="holo_light_control_activated">@color/holo_blue_light</color>
     <color name="holo_light_control_normal">#dacccccc</color>
     <color name="holo_light_button_pressed">#66666666</color>
     <color name="holo_light_button_normal">#b3cccccc</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index a19bc20..24d760f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -410,6 +410,9 @@
          radio is unable to find any MCC information to infer wifi country code from -->
     <bool translatable="false" name="config_wifi_revert_country_code_on_cellular_loss">false</bool>
 
+    <!-- Boolean indicating whether or not wifi firmware debugging is enabled -->
+    <bool translatable="false" name="config_wifi_enable_wifi_firmware_debugging">false</bool>
+
     <!-- Integer specifying the basic autojoin parameters -->
     <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_threshold">-65</integer>
     <integer translatable="false" name="config_wifi_framework_5GHz_preference_boost_factor">5</integer>
@@ -2211,6 +2214,10 @@
     <bool name="config_defaultWindowFeatureOptionsPanel">true</bool>
     <bool name="config_defaultWindowFeatureContextMenu">true</bool>
 
+    <!-- If true, the transition for a RemoteViews is read from a resource instead of using the
+         default scale-up transition. -->
+    <bool name="config_overrideRemoteViewsActivityTransition">false</bool>
+
     <!-- This config is used to check if the carrier requires converting destination
          number before sending out a SMS.
          Formats for this configuration as below:
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 8635a4f..2621bc9 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -45,6 +45,9 @@
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
     <dimen name="status_bar_edge_ignore">5dp</dimen>
 
+    <!-- Width of a divider bar used to resize docked stacks. -->
+    <dimen name="docked_stack_divider_thickness">24dp</dimen>
+
     <!-- Min width for a tablet device -->
     <dimen name="min_xlarge_screen_width">800dp</dimen>
 
diff --git a/core/res/res/values/dimens_material.xml b/core/res/res/values/dimens_material.xml
index 55bea9e..96a81d1 100644
--- a/core/res/res/values/dimens_material.xml
+++ b/core/res/res/values/dimens_material.xml
@@ -72,6 +72,7 @@
     <dimen name="text_size_title_material_toolbar">20dp</dimen>
     <dimen name="text_size_subtitle_material_toolbar">16dp</dimen>
     <dimen name="text_size_menu_material">16sp</dimen>
+    <dimen name="text_size_menu_header_material">14sp</dimen>
     <dimen name="text_size_body_2_material">14sp</dimen>
     <dimen name="text_size_body_1_material">14sp</dimen>
     <dimen name="text_size_caption_material">12sp</dimen>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 89d9bab..f4d0b39 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2674,6 +2674,8 @@
     <public type="attr" name="buttonGravity" />
     <public type="attr" name="collapseIcon" />
     <public type="attr" name="level" />
+    <public type="attr" name="contextPopupMenuStyle" />
+    <public type="attr" name="textAppearancePopupMenuHeader" />
 
     <public type="style" name="Theme.Material.DayNight" />
     <public type="style" name="Theme.Material.DayNight.DarkActionBar" />
diff --git a/core/res/res/values/styles_material.xml b/core/res/res/values/styles_material.xml
index 5dc14e3..38a1693 100644
--- a/core/res/res/values/styles_material.xml
+++ b/core/res/res/values/styles_material.xml
@@ -307,6 +307,10 @@
     <style name="TextAppearance.Material.Widget.PopupMenu"/>
     <style name="TextAppearance.Material.Widget.PopupMenu.Large" parent="TextAppearance.Material.Menu" />
     <style name="TextAppearance.Material.Widget.PopupMenu.Small" parent="TextAppearance.Material.Menu" />
+    <style name="TextAppearance.Material.Widget.PopupMenu.Header" parent="TextAppearance.Material.Subhead">
+        <item name="fontFamily">@string/font_family_title_material</item>
+        <item name="textSize">@dimen/text_size_menu_header_material</item>
+    </style>
 
     <style name="TextAppearance.Material.Widget.DropDownHint" parent="TextAppearance.Material.Menu" />
 
@@ -471,6 +475,7 @@
     <style name="Widget.Material.Button.Colored">
         <item name="background">@drawable/btn_colored_material</item>
         <item name="textAppearance">@style/TextAppearance.Material.Widget.Button.Inverse</item>
+        <item name="textColor">@color/btn_colored_text_material</item>
     </style>
 
     <!-- Small bordered ink button -->
@@ -487,7 +492,7 @@
 
     <!-- Colored borderless ink button -->
     <style name="Widget.Material.Button.Borderless.Colored">
-        <item name="textColor">@color/btn_colored_text_material</item>
+        <item name="textColor">@color/btn_colored_borderless_text_material</item>
     </style>
 
     <!-- Alert dialog button bar button -->
@@ -862,6 +867,11 @@
         <item name="dropDownHorizontalOffset">-4dip</item>
     </style>
 
+    <style name="Widget.Material.ContextPopupMenu" parent="Widget.Material.ListPopupWindow">
+        <item name="overlapAnchor">true</item>
+        <item name="popupEnterTransition">@null</item>
+    </style>
+
     <style name="Widget.Material.ActionButton">
         <item name="background">?attr/actionBarItemBackground</item>
         <item name="paddingStart">12dp</item>
diff --git a/core/res/res/values/styles_micro.xml b/core/res/res/values/styles_micro.xml
index c6052ff..05835e7 100644
--- a/core/res/res/values/styles_micro.xml
+++ b/core/res/res/values/styles_micro.xml
@@ -18,6 +18,7 @@
 
     <style name="Animation.Micro.Activity" parent="Animation.Material.Activity">
         <item name="activityOpenEnterAnimation">@anim/slide_in_micro</item>
+        <item name="activityOpenRemoteViewsEnterAnimation">@anim/slide_in_micro</item>
         <item name="activityOpenExitAnimation">@null</item>
         <item name="activityCloseEnterAnimation">@null</item>
         <item name="activityCloseExitAnimation">@anim/slide_out_micro</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 4edc8471..06de81d 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -307,6 +307,7 @@
   <java-symbol type="bool" name="config_wifi_enable_disconnection_debounce" />
   <java-symbol type="bool" name="config_wifi_enable_5GHz_preference" />
   <java-symbol type="bool" name="config_wifi_revert_country_code_on_cellular_loss" />
+  <java-symbol type="bool" name="config_wifi_enable_wifi_firmware_debugging" />
   <java-symbol type="bool" name="config_supportMicNearUltrasound" />
   <java-symbol type="bool" name="config_supportSpeakerNearUltrasound" />
   <java-symbol type="integer" name="config_wifi_framework_5GHz_preference_boost_threshold" />
@@ -1289,6 +1290,7 @@
   <java-symbol type="layout" name="number_picker" />
   <java-symbol type="layout" name="permissions_package_list_item" />
   <java-symbol type="layout" name="popup_menu_item_layout" />
+  <java-symbol type="layout" name="popup_menu_header_item_layout" />
   <java-symbol type="layout" name="remote_views_adapter_default_loading_view" />
   <java-symbol type="layout" name="search_bar" />
   <java-symbol type="layout" name="search_dropdown_item_icons_2line" />
@@ -1477,6 +1479,7 @@
   <java-symbol type="bool" name="config_showNavigationBar" />
   <java-symbol type="bool" name="config_supportAutoRotation" />
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
+  <java-symbol type="dimen" name="docked_stack_divider_thickness" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
@@ -1719,6 +1722,7 @@
   <java-symbol type="integer" name="config_undockedHdmiRotation" />
   <java-symbol type="integer" name="config_virtualKeyQuietTimeMillis" />
   <java-symbol type="layout" name="am_compat_mode_dialog" />
+  <java-symbol type="layout" name="docked_stack_divider" />
   <java-symbol type="layout" name="launch_warning" />
   <java-symbol type="layout" name="safe_mode" />
   <java-symbol type="layout" name="simple_list_item_2_single_choice" />
@@ -2188,6 +2192,7 @@
   <java-symbol type="bool" name="config_sms_force_7bit_encoding" />
   <java-symbol type="bool" name="config_defaultWindowFeatureOptionsPanel" />
   <java-symbol type="bool" name="config_defaultWindowFeatureContextMenu" />
+  <java-symbol type="bool" name="config_overrideRemoteViewsActivityTransition" />
 
   <java-symbol type="layout" name="simple_account_item" />
   <java-symbol type="array" name="config_sms_convert_destination_number_support" />
diff --git a/core/res/res/values/themes_material.xml b/core/res/res/values/themes_material.xml
index 3010190..59dfc92 100644
--- a/core/res/res/values/themes_material.xml
+++ b/core/res/res/values/themes_material.xml
@@ -93,6 +93,7 @@
 
         <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item>
         <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item>
+        <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item>
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.Material.Button</item>
@@ -283,6 +284,7 @@
         <item name="stackViewStyle">@style/Widget.Material.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Material.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
+        <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
@@ -449,6 +451,7 @@
 
         <item name="textAppearanceLargePopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Large</item>
         <item name="textAppearanceSmallPopupMenu">@style/TextAppearance.Material.Widget.PopupMenu.Small</item>
+        <item name="textAppearancePopupMenuHeader">@style/TextAppearance.Material.Widget.PopupMenu.Header</item>
 
         <!-- Button styles -->
         <item name="buttonStyle">@style/Widget.Material.Light.Button</item>
@@ -640,6 +643,7 @@
         <item name="stackViewStyle">@style/Widget.Material.Light.StackView</item>
         <item name="activityChooserViewStyle">@style/Widget.Material.Light.ActivityChooserView</item>
         <item name="fragmentBreadCrumbsStyle">@style/Widget.Material.FragmentBreadCrumbs</item>
+        <item name="contextPopupMenuStyle">@style/Widget.Material.ContextPopupMenu</item>
 
         <!-- Preference styles -->
         <item name="preferenceScreenStyle">@style/Preference.Material.PreferenceScreen</item>
diff --git a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
index e0b616c..3e83010 100644
--- a/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
+++ b/core/tests/coretests/apks/install_jni_lib/com_android_frameworks_coretests_JNITest.cpp
@@ -22,7 +22,7 @@
     return 1;
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     { "checkFunction", "()I", (void*) checkFunction },
 };
diff --git a/core/tests/coretests/src/android/widget/TextViewActivityTest.java b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
index b37688f..4db1d9a 100644
--- a/core/tests/coretests/src/android/widget/TextViewActivityTest.java
+++ b/core/tests/coretests/src/android/widget/TextViewActivityTest.java
@@ -17,6 +17,13 @@
 package android.widget;
 
 import static android.widget.espresso.TextViewActions.clickOnTextAtIndex;
+import static android.widget.espresso.TextViewActions.doubleTapAndDragOnText;
+import static android.widget.espresso.TextViewActions.doubleClickOnTextAtIndex;
+import static android.widget.espresso.TextViewActions.longPressAndDragOnText;
+import static android.widget.espresso.TextViewActions.longPressOnTextAtIndex;
+import static android.widget.espresso.TextViewAssertions.hasInsertionPointerAtIndex;
+import static android.widget.espresso.TextViewAssertions.hasSelection;
+import static android.widget.espresso.FloatingToolbarEspressoUtils.assertFloatingToolbarIsDisplayed;
 import static android.support.test.espresso.Espresso.onView;
 import static android.support.test.espresso.action.ViewActions.click;
 import static android.support.test.espresso.action.ViewActions.pressKey;
@@ -56,6 +63,7 @@
         getActivity();
 
         final String helloWorld = "Hello world!";
+        onView(withId(R.id.textview)).perform(click());
         onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
         onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("world")));
 
@@ -63,4 +71,103 @@
         onView(withId(R.id.textview)).perform(pressKey(KeyEvent.KEYCODE_FORWARD_DEL));
         onView(withId(R.id.textview)).check(matches(withText("Hello orld!")));
     }
+
+    @SmallTest
+    public void testLongPressToSelect() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello Kirk!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                longPressOnTextAtIndex(helloWorld.indexOf("Kirk")));
+
+        onView(withId(R.id.textview)).check(hasSelection("Kirk"));
+    }
+
+    @SmallTest
+    public void testLongPressEmptySpace() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello big round sun!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        // Move cursor somewhere else
+        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(helloWorld.indexOf("big")));
+        // Long-press at end of line.
+        onView(withId(R.id.textview)).perform(longPressOnTextAtIndex(helloWorld.length()));
+
+        onView(withId(R.id.textview)).check(hasInsertionPointerAtIndex(helloWorld.length()));
+    }
+
+    @SmallTest
+    public void testLongPressAndDragToSelect() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello little handsome boy!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                longPressAndDragOnText(helloWorld.indexOf("little"), helloWorld.indexOf(" boy!")));
+
+        onView(withId(R.id.textview)).check(hasSelection("little handsome"));
+    }
+
+    @SmallTest
+    public void testDoubleTapToSelect() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello SuetYi!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                doubleClickOnTextAtIndex(helloWorld.indexOf("SuetYi")));
+
+        onView(withId(R.id.textview)).check(hasSelection("SuetYi"));
+    }
+
+    @SmallTest
+    public void testDoubleTapAndDragToSelect() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello young beautiful girl!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                doubleTapAndDragOnText(helloWorld.indexOf("young"), helloWorld.indexOf(" girl!")));
+
+        onView(withId(R.id.textview)).check(hasSelection("young beautiful"));
+    }
+
+    @SmallTest
+    public void testSelectBackwordsByTouch() throws Exception {
+        getActivity();
+
+        final String helloWorld = "Hello king of the Jungle!";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(helloWorld));
+        onView(withId(R.id.textview)).perform(
+                doubleTapAndDragOnText(helloWorld.indexOf(" Jungle!"), helloWorld.indexOf("king")));
+
+        onView(withId(R.id.textview)).check(hasSelection("king of the"));
+    }
+
+    @SmallTest
+    public void testToolbarAppearsAfterSelection() throws Exception {
+        getActivity();
+
+        // It'll be nice to check that the toolbar is not visible (or does not exist) here
+        // I can't currently find a way to do this. I'll get to it later.
+
+        final String text = "Toolbar appears after selection.";
+        onView(withId(R.id.textview)).perform(click());
+        onView(withId(R.id.textview)).perform(typeTextIntoFocusedView(text));
+        onView(withId(R.id.textview)).perform(
+                longPressOnTextAtIndex(text.indexOf("appears")));
+
+        // It takes the toolbar less than 100ms to start to animate into screen.
+        // Ideally, we'll wait using the UiController, but I guess this works for now.
+        Thread.sleep(100);
+        assertFloatingToolbarIsDisplayed(getActivity());
+    }
 }
diff --git a/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
new file mode 100644
index 0000000..a0cd848
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/DragOnTextViewActions.java
@@ -0,0 +1,281 @@
+/*
+ * Copyright (C) 2015 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.widget.espresso;
+
+import static android.support.test.espresso.matcher.ViewMatchers.isAssignableFrom;
+import static android.support.test.espresso.matcher.ViewMatchers.isCompletelyDisplayed;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.allOf;
+
+import android.annotation.Nullable;
+import android.os.SystemClock;
+import android.support.test.espresso.UiController;
+import android.support.test.espresso.PerformException;
+import android.support.test.espresso.ViewAction;
+import android.support.test.espresso.action.CoordinatesProvider;
+import android.support.test.espresso.action.GeneralClickAction;
+import android.support.test.espresso.action.MotionEvents;
+import android.support.test.espresso.action.PrecisionDescriber;
+import android.support.test.espresso.action.Press;
+import android.support.test.espresso.action.Swiper;
+import android.support.test.espresso.action.Tap;
+import android.support.test.espresso.util.HumanReadables;
+import android.util.Log;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.widget.TextView;
+import org.hamcrest.Matcher;
+
+
+/**
+ * Drags on text in a TextView using touch events.<br>
+ * <br>
+ * View constraints:
+ * <ul>
+ * <li>must be a TextView displayed on screen
+ * <ul>
+ */
+public final class DragOnTextViewActions implements ViewAction {
+
+    /**
+     * Executes different "drag on text" types to given positions.
+     */
+    public enum Drag implements Swiper {
+
+        /**
+         * Starts a drag with a long-press.
+         */
+        LONG_PRESS {
+            private DownMotionPerformer downMotion = new DownMotionPerformer() {
+                @Override
+                public MotionEvent perform(
+                        UiController uiController, float[] coordinates, float[] precision) {
+                    MotionEvent downEvent = MotionEvents.sendDown(
+                            uiController, coordinates, precision)
+                            .down;
+                    // Duration before a press turns into a long press.
+                    // Factor 1.5 is needed, otherwise a long press is not safely detected.
+                    // See android.test.TouchUtils longClickView
+                    long longPressTimeout = (long) (ViewConfiguration.getLongPressTimeout() * 1.5f);
+                    uiController.loopMainThreadForAtLeast(longPressTimeout);
+                    return downEvent;
+                }
+            };
+
+            @Override
+            public Status sendSwipe(
+                    UiController uiController,
+                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
+                return sendLinearDrag(
+                        uiController, downMotion, startCoordinates, endCoordinates, precision);
+            }
+
+            @Override
+            public String toString() {
+                return "long press and drag to select";
+            }
+        },
+
+        /**
+         * Starts a drag with a double-tap.
+         */
+        DOUBLE_TAP {
+            private DownMotionPerformer downMotion = new DownMotionPerformer() {
+                @Override
+                @Nullable
+                public MotionEvent perform(
+                        UiController uiController,  float[] coordinates, float[] precision) {
+                    MotionEvent downEvent = MotionEvents.sendDown(
+                            uiController, coordinates, precision)
+                            .down;
+                    try {
+                        if (!MotionEvents.sendUp(uiController, downEvent)) {
+                            String logMessage = "Injection of up event as part of the double tap " +
+                                    "failed. Sending cancel event.";
+                            Log.d(TAG, logMessage);
+                            MotionEvents.sendCancel(uiController, downEvent);
+                            return null;
+                        }
+
+                        long doubleTapMinimumTimeout = ViewConfiguration.getDoubleTapMinTime();
+                        uiController.loopMainThreadForAtLeast(doubleTapMinimumTimeout);
+
+                        return MotionEvents.sendDown(uiController, coordinates, precision).down;
+                    } finally {
+                        downEvent.recycle();
+                    }
+                }
+            };
+
+            @Override
+            public Status sendSwipe(
+                    UiController uiController,
+                    float[] startCoordinates, float[] endCoordinates, float[] precision) {
+                return sendLinearDrag(
+                        uiController, downMotion, startCoordinates, endCoordinates, precision);
+            }
+
+            @Override
+            public String toString() {
+                return "double-tap and drag to select";
+            }
+        };
+
+        private static final String TAG = Drag.class.getSimpleName();
+
+        /** The number of move events to send for each drag. */
+        private static final int DRAG_STEP_COUNT = 10;
+
+        /** Length of time a drag should last for, in milliseconds. */
+        private static final int DRAG_DURATION = 1500;
+
+        private static Status sendLinearDrag(
+                UiController uiController, DownMotionPerformer downMotion,
+                float[] startCoordinates, float[] endCoordinates, float[] precision) {
+            float[][] steps = interpolate(startCoordinates, endCoordinates);
+            final int delayBetweenMovements = DRAG_DURATION / steps.length;
+
+            MotionEvent downEvent = downMotion.perform(uiController, startCoordinates, precision);
+            if (downEvent == null) {
+                return Status.FAILURE;
+            }
+
+            try {
+                for (int i = 0; i < steps.length; i++) {
+                    if (!MotionEvents.sendMovement(uiController, downEvent, steps[i])) {
+                        String logMessage = "Injection of move event as part of the drag failed. " +
+                                "Sending cancel event.";
+                        Log.e(TAG, logMessage);
+                        MotionEvents.sendCancel(uiController, downEvent);
+                        return Status.FAILURE;
+                    }
+
+                    long desiredTime = downEvent.getDownTime() + delayBetweenMovements * i;
+                    long timeUntilDesired = desiredTime - SystemClock.uptimeMillis();
+                    if (timeUntilDesired > 10) {
+                        // If the wait time until the next event isn't long enough, skip the wait
+                        // and execute the next event.
+                        uiController.loopMainThreadForAtLeast(timeUntilDesired);
+                    }
+                }
+
+                if (!MotionEvents.sendUp(uiController, downEvent, endCoordinates)) {
+                    String logMessage = "Injection of up event as part of the drag failed. " +
+                            "Sending cancel event.";
+                    Log.e(TAG, logMessage);
+                    MotionEvents.sendCancel(uiController, downEvent);
+                    return Status.FAILURE;
+                }
+            } finally {
+                downEvent.recycle();
+            }
+            return Status.SUCCESS;
+        }
+
+        private static float[][] interpolate(float[] start, float[] end) {
+            float[][] res = new float[DRAG_STEP_COUNT][2];
+
+            for (int i = 1; i < DRAG_STEP_COUNT + 1; i++) {
+                res[i - 1][0] = start[0] + (end[0] - start[0]) * i / (DRAG_STEP_COUNT + 2f);
+                res[i - 1][1] = start[1] + (end[1] - start[1]) * i / (DRAG_STEP_COUNT + 2f);
+            }
+
+            return res;
+        }
+    }
+
+    /**
+     * Interface to implement different "down motion" types.
+     */
+    private interface DownMotionPerformer {
+        /**
+         * Performs and returns a down motion.
+         *
+         * @param uiController a UiController to use to send MotionEvents to the screen.
+         * @param coordinates a float[] with x and y values of center of the tap.
+         * @param precision  a float[] with x and y values of precision of the tap.
+         * @return the down motion event or null if the down motion event failed.
+         */
+        @Nullable
+        MotionEvent perform(UiController uiController, float[] coordinates, float[] precision);
+    }
+
+    private final Swiper mDragger;
+    private final CoordinatesProvider mStartCoordinatesProvider;
+    private final CoordinatesProvider mEndCoordinatesProvider;
+    private final PrecisionDescriber mPrecisionDescriber;
+
+    public DragOnTextViewActions(
+            Swiper dragger,
+            CoordinatesProvider startCoordinatesProvider,
+            CoordinatesProvider endCoordinatesProvider,
+            PrecisionDescriber precisionDescriber) {
+        mDragger = checkNotNull(dragger);
+        mStartCoordinatesProvider = checkNotNull(startCoordinatesProvider);
+        mEndCoordinatesProvider = checkNotNull(endCoordinatesProvider);
+        mPrecisionDescriber = checkNotNull(precisionDescriber);
+    }
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public Matcher<View> getConstraints() {
+        return allOf(isCompletelyDisplayed(), isAssignableFrom(TextView.class));
+    }
+
+    @Override
+    public void perform(UiController uiController, View view) {
+        checkNotNull(uiController);
+        checkNotNull(view);
+
+        float[] startCoordinates = mStartCoordinatesProvider.calculateCoordinates(view);
+        float[] endCoordinates = mEndCoordinatesProvider.calculateCoordinates(view);
+        float[] precision = mPrecisionDescriber.describePrecision();
+
+        Swiper.Status status;
+
+        try {
+            status = mDragger.sendSwipe(
+                    uiController, startCoordinates, endCoordinates, precision);
+        } catch (RuntimeException re) {
+            throw new PerformException.Builder()
+                    .withActionDescription(this.getDescription())
+                    .withViewDescription(HumanReadables.describe(view))
+                    .withCause(re)
+                    .build();
+        }
+
+        int duration = ViewConfiguration.getPressedStateDuration();
+        // ensures that all work enqueued to process the swipe has been run.
+        if (duration > 0) {
+            uiController.loopMainThreadForAtLeast(duration);
+        }
+
+        if (status == Swiper.Status.FAILURE) {
+            throw new PerformException.Builder()
+                    .withActionDescription(getDescription())
+                    .withViewDescription(HumanReadables.describe(view))
+                    .withCause(new RuntimeException(getDescription() + " failed"))
+                    .build();
+        }
+    }
+
+    @Override
+    public String getDescription() {
+        return mDragger.toString();
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
new file mode 100644
index 0000000..fc01d84
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/FloatingToolbarEspressoUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2015 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.widget.espresso;
+
+import static android.support.test.espresso.Espresso.onView;
+import static android.support.test.espresso.assertion.ViewAssertions.matches;
+import static android.support.test.espresso.matcher.RootMatchers.withDecorView;
+import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
+import static android.support.test.espresso.matcher.ViewMatchers.withTagValue;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+
+import android.app.Activity;
+import com.android.internal.widget.FloatingToolbar;
+
+/**
+ * Espresso utility methods for the floating toolbar.
+ */
+public class FloatingToolbarEspressoUtils {
+
+
+    private FloatingToolbarEspressoUtils() {}
+
+    /**
+     * Asserts that the floating toolbar is displayed on screen.
+     *
+     * @throws AssertionError if the assertion fails
+     */
+    public static void assertFloatingToolbarIsDisplayed(Activity activity) {
+        onView(withTagValue(is((Object) FloatingToolbar.FLOATING_TOOLBAR_TAG)))
+                .inRoot(withDecorView(not(is(activity.getWindow().getDecorView()))))
+                .check(matches(isDisplayed()));
+    }
+
+}
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
index 425dccd..835b1b9 100644
--- a/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewActions.java
@@ -18,7 +18,6 @@
 
 import static android.support.test.espresso.action.ViewActions.actionWithAssertions;
 
-import android.content.res.Resources;
 import android.support.test.espresso.PerformException;
 import android.support.test.espresso.ViewAction;
 import android.support.test.espresso.action.CoordinatesProvider;
@@ -27,8 +26,6 @@
 import android.support.test.espresso.action.Tap;
 import android.support.test.espresso.util.HumanReadables;
 import android.text.Layout;
-import android.util.DisplayMetrics;
-import android.util.TypedValue;
 import android.view.View;
 import android.widget.TextView;
 
@@ -40,12 +37,14 @@
     private TextViewActions() {}
 
     /**
-     * Returns an action that clicks on text at an index on the text view.<br>
+     * Returns an action that clicks on text at an index on the TextView.<br>
      * <br>
      * View constraints:
      * <ul>
-     * <li>must be a text view displayed on screen
+     * <li>must be a TextView displayed on screen
      * <ul>
+     *
+     * @param index The index of the TextView's text to click on.
      */
     public static ViewAction clickOnTextAtIndex(int index) {
         return actionWithAssertions(
@@ -53,6 +52,78 @@
     }
 
     /**
+     * Returns an action that double-clicks on text at an index on the TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param index The index of the TextView's text to double-click on.
+     */
+    public static ViewAction doubleClickOnTextAtIndex(int index) {
+        return actionWithAssertions(
+                new GeneralClickAction(Tap.DOUBLE, new TextCoordinates(index), Press.FINGER));
+    }
+
+    /**
+     * Returns an action that long presses on text at an index on the TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param index The index of the TextView's text to long press on.
+     */
+    public static ViewAction longPressOnTextAtIndex(int index) {
+        return actionWithAssertions(
+                new GeneralClickAction(Tap.LONG, new TextCoordinates(index), Press.FINGER));
+    }
+
+    /**
+     * Returns an action that long presses then drags on text from startIndex to endIndex on the
+     * TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param startIndex The index of the TextView's text to start a drag from
+     * @param endIndex The index of the TextView's text to end the drag at
+     */
+    public static ViewAction longPressAndDragOnText(int startIndex, int endIndex) {
+        return actionWithAssertions(
+                new DragOnTextViewActions(
+                        DragOnTextViewActions.Drag.LONG_PRESS,
+                        new TextCoordinates(startIndex),
+                        new TextCoordinates(endIndex),
+                        Press.FINGER));
+    }
+
+    /**
+     * Returns an action that double taps then drags on text from startIndex to endIndex on the
+     * TextView.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a TextView displayed on screen
+     * <ul>
+     *
+     * @param startIndex The index of the TextView's text to start a drag from
+     * @param endIndex The index of the TextView's text to end the drag at
+     */
+    public static ViewAction doubleTapAndDragOnText(int startIndex, int endIndex) {
+        return actionWithAssertions(
+                new DragOnTextViewActions(
+                        DragOnTextViewActions.Drag.DOUBLE_TAP,
+                        new TextCoordinates(startIndex),
+                        new TextCoordinates(endIndex),
+                        Press.FINGER));
+    }
+
+    /**
      * A provider of the x, y coordinates of the text at the specified index in a text view.
      */
     private static final class TextCoordinates implements CoordinatesProvider {
diff --git a/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
new file mode 100644
index 0000000..37c7425
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/espresso/TextViewAssertions.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 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.widget.espresso;
+
+import static android.support.test.espresso.matcher.ViewMatchers.assertThat;
+import static com.android.internal.util.Preconditions.checkNotNull;
+import static org.hamcrest.Matchers.is;
+
+import android.support.test.espresso.NoMatchingViewException;
+import android.support.test.espresso.ViewAssertion;
+import android.view.View;
+import android.widget.TextView;
+
+import junit.framework.AssertionFailedError;
+import org.hamcrest.Matcher;
+
+/**
+ * A collection of assertions on a {@link android.widget.TextView}.
+ */
+public final class TextViewAssertions {
+
+    private TextViewAssertions() {}
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+     * selection.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a text view displayed on screen
+     * <ul>
+     *
+     * @param selection  The expected selection.
+     */
+    public static ViewAssertion hasSelection(String selection) {
+        return hasSelection(is(selection));
+    }
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the text view has a specified
+     * selection.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a text view displayed on screen
+     * <ul>
+     *
+     * @param selection  A matcher representing the expected selection.
+     */
+    public static ViewAssertion hasSelection(Matcher<String> selection) {
+        return new TextSelectionAssertion(selection);
+    }
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at
+     * a specified index.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a text view displayed on screen
+     * <ul>
+     *
+     * @param index  The expected index.
+     */
+    public static ViewAssertion hasInsertionPointerAtIndex(int index) {
+        return hasInsertionPointerAtIndex(is(index));
+    }
+
+    /**
+     * Returns a {@link ViewAssertion} that asserts that the text view insertion pointer is at
+     * a specified index.<br>
+     * <br>
+     * View constraints:
+     * <ul>
+     * <li>must be a text view displayed on screen
+     * <ul>
+     *
+     * @param index  A matcher representing the expected index.
+     */
+    public static ViewAssertion hasInsertionPointerAtIndex(final Matcher<Integer> index) {
+        return new ViewAssertion() {
+            @Override
+            public void check(View view, NoMatchingViewException exception) {
+                if (view instanceof TextView) {
+                    TextView textView = (TextView) view;
+                    int selectionStart = textView.getSelectionStart();
+                    int selectionEnd = textView.getSelectionEnd();
+                    try {
+                        assertThat(selectionStart, index);
+                        assertThat(selectionEnd, index);
+                    } catch (IndexOutOfBoundsException e) {
+                        throw new AssertionFailedError(e.getMessage());
+                    }
+                } else {
+                    throw new AssertionFailedError("TextView not found");
+                }
+            }
+        };
+    }
+
+    /**
+     * A {@link ViewAssertion} to check the selected text in a {@link TextView}.
+     */
+    private static final class TextSelectionAssertion implements ViewAssertion {
+
+        private final Matcher<String> mSelection;
+
+        public TextSelectionAssertion(Matcher<String> selection) {
+            mSelection = checkNotNull(selection);
+        }
+
+        @Override
+        public void check(View view, NoMatchingViewException exception) {
+            if (view instanceof TextView) {
+                TextView textView = (TextView) view;
+                int selectionStart = textView.getSelectionStart();
+                int selectionEnd = textView.getSelectionEnd();
+                try {
+                    String selectedText = textView.getText()
+                            .subSequence(selectionStart, selectionEnd)
+                            .toString();
+                    assertThat(selectedText, mSelection);
+                } catch (IndexOutOfBoundsException e) {
+                    throw new AssertionFailedError(e.getMessage());
+                }
+            } else {
+                throw new AssertionFailedError("TextView not found");
+            }
+        }
+    }
+}
diff --git a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
index 4c16154..67b12d7 100644
--- a/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/32/jni/native.cpp
@@ -30,7 +30,7 @@
 
 static const char *classPathName = "com/framework/shareduid/bit32/Native";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
   {"add", "(II)I", (void*)add },
 };
 
@@ -38,7 +38,7 @@
  * Register several native methods for one class.
  */
 static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
+    const JNINativeMethod* gMethods, int numMethods)
 {
     jclass clazz;
 
diff --git a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
index c2f9f529..342b3bc 100644
--- a/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/64/jni/native.cpp
@@ -30,7 +30,7 @@
 
 static const char *classPathName = "com/framework/shareduid/bit64/Native";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
   {"add", "(II)I", (void*)add },
 };
 
@@ -38,7 +38,7 @@
  * Register several native methods for one class.
  */
 static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
+    const JNINativeMethod* gMethods, int numMethods)
 {
     jclass clazz;
 
diff --git a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
index 5d3ca06..9b38e3e 100644
--- a/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
+++ b/core/tests/hosttests/test-apps/SharedUid/dual/jni/native.cpp
@@ -30,7 +30,7 @@
 
 static const char *classPathName = "com/framework/shareduid/dual/Native";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
   {"add", "(II)I", (void*)add },
 };
 
@@ -38,7 +38,7 @@
  * Register several native methods for one class.
  */
 static int registerNativeMethods(JNIEnv* env, const char* className,
-    JNINativeMethod* gMethods, int numMethods)
+    const JNINativeMethod* gMethods, int numMethods)
 {
     jclass clazz;
 
diff --git a/docs/html/tools/support-library/index.jd b/docs/html/tools/support-library/index.jd
index 9dc0ed1..22ad0c9 100644
--- a/docs/html/tools/support-library/index.jd
+++ b/docs/html/tools/support-library/index.jd
@@ -665,7 +665,7 @@
           <li>Added support for a Collapse icon description in the {@link android.support.v7.widget.Toolbar}
           class.</li>
           <li>Updated the {@link android.support.v7.widget.SearchView} widget to support displaying
-          the {@link android.support.v7.mediarouter.R.attr#commitIcon}. </li>
+          the {@link android.support.v7.appcompat.R.attr#commitIcon}. </li>
           <li>Removed the <code>buttonGravity</code> attribute from the
           {@link android.support.v7.widget.Toolbar} class. </li>
         </ul>
diff --git a/drm/jni/android_drm_DrmManagerClient.cpp b/drm/jni/android_drm_DrmManagerClient.cpp
index 52597e1..63fe8ace 100644
--- a/drm/jni/android_drm_DrmManagerClient.cpp
+++ b/drm/jni/android_drm_DrmManagerClient.cpp
@@ -702,7 +702,7 @@
     return status;
 }
 
-static JNINativeMethod nativeMethods[] = {
+static const JNINativeMethod nativeMethods[] = {
 
     {"_initialize", "()I",
                                     (void*)android_drm_DrmManagerClient_initialize},
diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java
index 6582b7e..58de87a 100644
--- a/graphics/java/android/graphics/Paint.java
+++ b/graphics/java/android/graphics/Paint.java
@@ -1526,18 +1526,18 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, index, count, mBidiFlags));
+            return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text,
+                    index, count, index, count, mBidiFlags, null, 0));
         }
 
         final float oldSize = getTextSize();
-        setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, index, count, mBidiFlags);
+        setTextSize(oldSize * mCompatScaling);
+        float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index,
+                count, mBidiFlags, null, 0);
         setTextSize(oldSize);
         return (float) Math.ceil(w*mInvCompatScaling);
     }
 
-    private native float native_measureText(char[] text, int index, int count, int bidiFlags);
-
     /**
      * Return the width of the text.
      *
@@ -1558,18 +1558,17 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, start, end, mBidiFlags));
+            return (float) Math.ceil(native_getTextAdvances(mNativePaint, mNativeTypeface, text,
+                    start, end, start, end, mBidiFlags, null, 0));
         }
-
         final float oldSize = getTextSize();
-        setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, start, end, mBidiFlags);
+        setTextSize(oldSize * mCompatScaling);
+        float w = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start,
+                end, mBidiFlags, null, 0);
         setTextSize(oldSize);
-        return (float) Math.ceil(w*mInvCompatScaling);
+        return (float) Math.ceil(w * mInvCompatScaling);
     }
 
-    private native float native_measureText(String text, int start, int end, int bidiFlags);
-
     /**
      * Return the width of the text.
      *
@@ -1580,23 +1579,9 @@
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
-
-        if (text.length() == 0) {
-            return 0f;
-        }
-
-        if (!mHasCompatScaling) {
-            return (float) Math.ceil(native_measureText(text, mBidiFlags));
-        }
-        final float oldSize = getTextSize();
-        setTextSize(oldSize*mCompatScaling);
-        float w = native_measureText(text, mBidiFlags);
-        setTextSize(oldSize);
-        return (float) Math.ceil(w*mInvCompatScaling);
+        return measureText(text, 0, text.length());
     }
 
-    private native float native_measureText(String text, int bidiFlags);
-
     /**
      * Return the width of the text.
      *
@@ -1795,17 +1780,20 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
+            native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
+                    mBidiFlags, widths, 0);
+            return count;
         }
 
         final float oldSize = getTextSize();
-        setTextSize(oldSize*mCompatScaling);
-        int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, index, count, mBidiFlags, widths);
+        setTextSize(oldSize * mCompatScaling);
+        native_getTextAdvances(mNativePaint, mNativeTypeface, text, index, count, index, count,
+                mBidiFlags, widths, 0);
         setTextSize(oldSize);
-        for (int i=0; i<res; i++) {
+        for (int i = 0; i < count; i++) {
             widths[i] *= mInvCompatScaling;
         }
-        return res;
+        return count;
     }
 
     /**
@@ -1860,7 +1848,7 @@
      * @param end    The end of the text slice to measure
      * @param widths array to receive the advance widths of the characters.
      *               Must be at least a large as the text.
-     * @return       the number of unichars in the specified text.
+     * @return       the number of code units in the specified text.
      */
     public int getTextWidths(String text, int start, int end, float[] widths) {
         if (text == null) {
@@ -1877,17 +1865,20 @@
             return 0;
         }
         if (!mHasCompatScaling) {
-            return native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
+            native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
+                    mBidiFlags, widths, 0);
+            return end - start;
         }
 
         final float oldSize = getTextSize();
-        setTextSize(oldSize*mCompatScaling);
-        int res = native_getTextWidths(mNativePaint, mNativeTypeface, text, start, end, mBidiFlags, widths);
+        setTextSize(oldSize * mCompatScaling);
+        native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end, start, end,
+                mBidiFlags, widths, 0);
         setTextSize(oldSize);
-        for (int i=0; i<res; i++) {
+        for (int i = 0; i < end - start; i++) {
             widths[i] *= mInvCompatScaling;
         }
-        return res;
+        return end - start;
     }
 
     /**
@@ -1896,7 +1887,7 @@
      * @param text   The text to measure
      * @param widths array to receive the advance widths of the characters.
      *               Must be at least a large as the text.
-     * @return       the number of unichars in the specified text.
+     * @return       the number of code units in the specified text.
      */
     public int getTextWidths(String text, float[] widths) {
         return getTextWidths(text, 0, text.length(), widths);
@@ -1929,14 +1920,16 @@
             return 0f;
         }
         if (!mHasCompatScaling) {
-            return native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
-                    contextIndex, contextCount, isRtl, advances, advancesIndex);
+            return native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
+                    contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+                    advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        float res = native_getTextRunAdvances(mNativePaint, mNativeTypeface, chars, index, count,
-                contextIndex, contextCount, isRtl, advances, advancesIndex);
+        float res = native_getTextAdvances(mNativePaint, mNativeTypeface, chars, index, count,
+                contextIndex, contextCount, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+                advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -2039,7 +2032,6 @@
      */
     public float getTextRunAdvances(String text, int start, int end, int contextStart,
             int contextEnd, boolean isRtl, float[] advances, int advancesIndex) {
-
         if (text == null) {
             throw new IllegalArgumentException("text cannot be null");
         }
@@ -2056,14 +2048,16 @@
         }
 
         if (!mHasCompatScaling) {
-            return native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
-                    contextStart, contextEnd, isRtl, advances, advancesIndex);
+            return native_getTextAdvances(mNativePaint, mNativeTypeface, text, start, end,
+                    contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+                    advancesIndex);
         }
 
         final float oldSize = getTextSize();
         setTextSize(oldSize * mCompatScaling);
-        float totalAdvance = native_getTextRunAdvances(mNativePaint, mNativeTypeface, text, start, end,
-                contextStart, contextEnd, isRtl, advances, advancesIndex);
+        float totalAdvance = native_getTextAdvances(mNativePaint, mNativeTypeface, text, start,
+                end, contextStart, contextEnd, isRtl ? BIDI_FORCE_RTL : BIDI_FORCE_LTR, advances,
+                advancesIndex);
         setTextSize(oldSize);
 
         if (advances != null) {
@@ -2511,21 +2505,16 @@
     private static native void native_setTextLocale(long native_object,
                                                     String locale);
 
-    private static native int native_getTextWidths(long native_object, long native_typeface,
-                            char[] text, int index, int count, int bidiFlags, float[] widths);
-    private static native int native_getTextWidths(long native_object, long native_typeface,
-                            String text, int start, int end, int bidiFlags, float[] widths);
-
     private static native int native_getTextGlyphs(long native_object,
             String text, int start, int end, int contextStart, int contextEnd,
             int flags, char[] glyphs);
 
-    private static native float native_getTextRunAdvances(long native_object, long native_typeface,
+    private static native float native_getTextAdvances(long native_object, long native_typeface,
             char[] text, int index, int count, int contextIndex, int contextCount,
-            boolean isRtl, float[] advances, int advancesIndex);
-    private static native float native_getTextRunAdvances(long native_object, long native_typeface,
+            int bidiFlags, float[] advances, int advancesIndex);
+    private static native float native_getTextAdvances(long native_object, long native_typeface,
             String text, int start, int end, int contextStart, int contextEnd,
-            boolean isRtl, float[] advances, int advancesIndex);
+            int bidiFlags, float[] advances, int advancesIndex);
 
     private native int native_getTextRunCursor(long native_object, char[] text,
             int contextStart, int contextLength, int dir, int offset, int cursorOpt);
diff --git a/graphics/tests/graphicstests/src/android/graphics/PaintTest.java b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
new file mode 100644
index 0000000..b67aa7d
--- /dev/null
+++ b/graphics/tests/graphicstests/src/android/graphics/PaintTest.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2015 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.graphics;
+
+import android.test.AndroidTestCase;
+
+public class PaintTest extends AndroidTestCase {
+    public void testGetTextRunAdvances() {
+        {
+            // LTR
+            String text = "abcdef";
+            assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), false, true);
+            assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), false, false);
+        }
+        {
+            // RTL
+            final String text =
+                    "\u0645\u0627\u0020\u0647\u064A\u0020\u0627\u0644\u0634" +
+                    "\u0641\u0631\u0629\u0020\u0627\u0644\u0645\u0648\u062D" +
+                    "\u062F\u0629\u0020\u064A\u0648\u0646\u064A\u0643\u0648" +
+                    "\u062F\u061F";
+            assertGetTextRunAdvances(text, 0, text.length(), 0, text.length(), true, true);
+            assertGetTextRunAdvances(text, 1, text.length() - 1, 0, text.length(), true, false);
+        }
+    }
+
+    private void assertGetTextRunAdvances(String str, int start, int end,
+            int contextStart, int contextEnd, boolean isRtl, boolean compareWithOtherMethods) {
+        Paint p = new Paint();
+
+        final int count = end - start;
+        final float[][] advanceArrays = new float[4][count];
+
+        final float advance = p.getTextRunAdvances(str, start, end, contextStart, contextEnd,
+                isRtl, advanceArrays[0], 0);
+
+        char chars[] = str.toCharArray();
+        final float advance_c = p.getTextRunAdvances(chars, start, count, contextStart,
+                contextEnd - contextStart, isRtl, advanceArrays[1], 0);
+        assertEquals(advance, advance_c, 1.0f);
+
+        for (int c = 1; c < count; ++c) {
+            final float firstPartAdvance = p.getTextRunAdvances(str, start, start + c,
+                    contextStart, contextEnd, isRtl, advanceArrays[2], 0);
+            final float secondPartAdvance = p.getTextRunAdvances(str, start + c, end,
+                    contextStart, contextEnd, isRtl, advanceArrays[2], c);
+            assertEquals(advance, firstPartAdvance + secondPartAdvance, 1.0f);
+
+
+            final float firstPartAdvance_c = p.getTextRunAdvances(chars, start, c,
+                    contextStart, contextEnd - contextStart, isRtl, advanceArrays[3], 0);
+            final float secondPartAdvance_c = p.getTextRunAdvances(chars, start + c,
+                    count - c, contextStart, contextEnd - contextStart, isRtl,
+                    advanceArrays[3], c);
+            assertEquals(advance, firstPartAdvance_c + secondPartAdvance_c, 1.0f);
+            assertEquals(firstPartAdvance, firstPartAdvance_c, 1.0f);
+            assertEquals(secondPartAdvance, secondPartAdvance_c, 1.0f);
+
+            for (int i = 1; i < advanceArrays.length; i++) {
+                for (int j = 0; j < count; j++) {
+                    assertEquals(advanceArrays[0][j], advanceArrays[i][j], 1.0f);
+                }
+            }
+
+            // Compare results with measureText, getRunAdvance, and getTextWidths.
+            if (compareWithOtherMethods && start == contextStart && end == contextEnd) {
+                assertEquals(advance, p.measureText(str, start, end), 1.0f);
+                assertEquals(advance, p.getRunAdvance(
+                        str, start, end, contextStart, contextEnd, isRtl, end), 1.0f);
+
+                final float[] widths = new float[count];
+                p.getTextWidths(str, start, end, widths);
+                for (int i = 0; i < count; i++) {
+                    assertEquals(advanceArrays[0][i], widths[i], 1.0f);
+                }
+            }
+        }
+    }
+
+    public void testGetTextRunAdvances_invalid() {
+        Paint p = new Paint();
+        String text = "test";
+
+        try {
+            p.getTextRunAdvances((String)null, 0, 0, 0, 0, false, null, 0);
+            fail("Should throw an IllegalArgumentException.");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            p.getTextRunAdvances((CharSequence)null, 0, 0, 0, 0, false, null, 0);
+            fail("Should throw an IllegalArgumentException.");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            p.getTextRunAdvances((char[])null, 0, 0, 0, 0, false, null, 0);
+            fail("Should throw an IllegalArgumentException.");
+        } catch (IllegalArgumentException e) {
+        }
+
+        try {
+            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
+                    new float[text.length() - 1], 0);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+
+        try {
+            p.getTextRunAdvances(text, 0, text.length(), 0, text.length(), false,
+                    new float[text.length()], 1);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+
+        // 0 > contextStart
+        try {
+            p.getTextRunAdvances(text, 0, text.length(), -1, text.length(), false, null, 0);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+
+        // contextStart > start
+        try {
+            p.getTextRunAdvances(text, 0, text.length(), 1, text.length(), false, null, 0);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+
+        // start > end
+        try {
+            p.getTextRunAdvances(text, 1, 0, 0, text.length(), false, null, 0);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+
+        // end > contextEnd
+        try {
+            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() - 1, false, null, 0);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+
+        // contextEnd > text.length
+        try {
+            p.getTextRunAdvances(text, 0, text.length(), 0, text.length() + 1, false, null, 0);
+            fail("Should throw an IndexOutOfBoundsException.");
+        } catch (IndexOutOfBoundsException e) {
+        }
+    }
+}
diff --git a/media/java/android/media/SRTRenderer.java b/media/java/android/media/SRTRenderer.java
index ee4edee..a3e2abd 100644
--- a/media/java/android/media/SRTRenderer.java
+++ b/media/java/android/media/SRTRenderer.java
@@ -165,7 +165,6 @@
             return;
         }
 
-        final int _ = 0;
         for (Cue cue : activeCues) {
             TextTrackCue ttc = (TextTrackCue) cue;
 
@@ -184,7 +183,8 @@
             parcel.writeInt(buf.length);
             parcel.writeByteArray(buf);
 
-            Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, _, _, parcel);
+            Message msg = mEventHandler.obtainMessage(MEDIA_TIMED_TEXT, 0 /* arg1 */, 0 /* arg2 */,
+                    parcel);
             mEventHandler.sendMessage(msg);
         }
         activeCues.clear();
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index 3cd157e..95cb520 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -18,6 +18,8 @@
 
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
 import android.os.ParcelFileDescriptor;
 
 /**
@@ -47,7 +49,7 @@
 
     /**
      * Opens the MTP device.  Once the device is open it takes ownership of the
-     * {@link android.hardware.usb.UsbDeviceConnection}.  
+     * {@link android.hardware.usb.UsbDeviceConnection}.
      * The connection will be closed when you call {@link #close()}
      * The connection will also be closed if this method fails.
      *
@@ -278,6 +280,38 @@
         return native_send_object_info(info);
     }
 
+    /**
+     * Reads an event from the device. It blocks the current thread until it gets an event.
+     * It throws OperationCanceledException if it is cancelled by signal.
+     *
+     * @param signal signal for cancellation
+     * @return obtained event
+     */
+    public MtpEvent readEvent(CancellationSignal signal) {
+        final int handle = native_submit_event_request();
+
+        if (handle < 0) {
+            throw new IllegalStateException("Other thread is reading an event.");
+        }
+
+        if (signal != null) {
+            signal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
+                @Override
+                public void onCancel() {
+                    native_discard_event_request(handle);
+                }
+            });
+        }
+
+        try {
+            return native_reap_event_request(handle);
+        } finally {
+            if (signal != null) {
+                signal.setOnCancelListener(null);
+            }
+        }
+    }
+
     // used by the JNI code
     private long mNativeContext;
 
@@ -297,4 +331,7 @@
     private native boolean native_import_file(int objectHandle, int fd);
     private native boolean native_send_object(int objectHandle, int size, int fd);
     private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
+    private native int native_submit_event_request();
+    private native MtpEvent native_reap_event_request(int handle);
+    private native void native_discard_event_request(int handle);
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/media/java/android/mtp/MtpEvent.java
similarity index 68%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to media/java/android/mtp/MtpEvent.java
index c47d194..0fa7d93 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/media/java/android/mtp/MtpEvent.java
@@ -13,9 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package android.mtp;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+/**
+ * This class encapsulates information about a MTP event.
+ */
+public class MtpEvent {
+    private int mEventCode;
+
+    /**
+     * Returns event code of MTP event.
+     *
+     * @return event code
+     */
+    public int getEventCode() { return mEventCode; }
 }
diff --git a/media/jni/android_media_AmrInputStream.cpp b/media/jni/android_media_AmrInputStream.cpp
index afb5d5c..b56a364 100644
--- a/media/jni/android_media_AmrInputStream.cpp
+++ b/media/jni/android_media_AmrInputStream.cpp
@@ -119,7 +119,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"GsmAmrEncoderNew",        "()J",        (void*)android_media_AmrInputStream_GsmAmrEncoderNew},
     {"GsmAmrEncoderInitialize", "(J)V",       (void*)android_media_AmrInputStream_GsmAmrEncoderInitialize},
     {"GsmAmrEncoderEncode",     "(J[BI[BI)I", (void*)android_media_AmrInputStream_GsmAmrEncoderEncode},
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 0034b07..3ffdb17 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -1253,7 +1253,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gImageReaderMethods[] = {
+static const JNINativeMethod gImageReaderMethods[] = {
     {"nativeClassInit",        "()V",                        (void*)ImageReader_classInit },
     {"nativeInit",             "(Ljava/lang/Object;IIII)V",  (void*)ImageReader_init },
     {"nativeClose",            "()V",                        (void*)ImageReader_close },
@@ -1263,7 +1263,7 @@
     {"nativeDetachImage",      "(Landroid/media/Image;)I",   (void*)ImageReader_detachImage },
 };
 
-static JNINativeMethod gImageMethods[] = {
+static const JNINativeMethod gImageMethods[] = {
     {"nativeImageGetBuffer",   "(II)Ljava/nio/ByteBuffer;",   (void*)Image_getByteBuffer },
     {"nativeCreatePlane",      "(II)Landroid/media/ImageReader$SurfaceImage$SurfacePlane;",
                                                               (void*)Image_createSurfacePlane },
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 93a4426..e8f680f 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -1798,7 +1798,7 @@
     android_media_MediaCodec_release(env, thiz);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "native_release", "()V", (void *)android_media_MediaCodec_release },
 
     { "native_reset", "()V", (void *)android_media_MediaCodec_reset },
diff --git a/media/jni/android_media_MediaCodecList.cpp b/media/jni/android_media_MediaCodecList.cpp
index 82dd48d..de9bf1f 100644
--- a/media/jni/android_media_MediaCodecList.cpp
+++ b/media/jni/android_media_MediaCodecList.cpp
@@ -286,7 +286,7 @@
 static void android_media_MediaCodecList_native_init(JNIEnv* /* env */) {
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "native_getCodecCount", "()I", (void *)android_media_MediaCodecList_getCodecCount },
     { "getCodecName", "(I)Ljava/lang/String;",
       (void *)android_media_MediaCodecList_getCodecName },
diff --git a/media/jni/android_media_MediaCrypto.cpp b/media/jni/android_media_MediaCrypto.cpp
index d7968d2..e414f48 100644
--- a/media/jni/android_media_MediaCrypto.cpp
+++ b/media/jni/android_media_MediaCrypto.cpp
@@ -316,7 +316,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaCrypto_release },
     { "native_init", "()V", (void *)android_media_MediaCrypto_native_init },
 
diff --git a/media/jni/android_media_MediaDrm.cpp b/media/jni/android_media_MediaDrm.cpp
index 9ec0312..275de1ad 100644
--- a/media/jni/android_media_MediaDrm.cpp
+++ b/media/jni/android_media_MediaDrm.cpp
@@ -1455,7 +1455,7 @@
 }
 
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaDrm_release },
     { "native_init", "()V", (void *)android_media_MediaDrm_native_init },
 
diff --git a/media/jni/android_media_MediaExtractor.cpp b/media/jni/android_media_MediaExtractor.cpp
index 4e9b726..96c12dd 100644
--- a/media/jni/android_media_MediaExtractor.cpp
+++ b/media/jni/android_media_MediaExtractor.cpp
@@ -769,7 +769,7 @@
     android_media_MediaExtractor_release(env, thiz);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "release", "()V", (void *)android_media_MediaExtractor_release },
 
     { "getTrackCount", "()I", (void *)android_media_MediaExtractor_getTrackCount },
diff --git a/media/jni/android_media_MediaHTTPConnection.cpp b/media/jni/android_media_MediaHTTPConnection.cpp
index 393003d..fa0b43f 100644
--- a/media/jni/android_media_MediaHTTPConnection.cpp
+++ b/media/jni/android_media_MediaHTTPConnection.cpp
@@ -154,7 +154,7 @@
     return n;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "native_getIMemory", "()Landroid/os/IBinder;",
       (void *)android_media_MediaHTTPConnection_native_getIMemory },
 
diff --git a/media/jni/android_media_MediaMetadataRetriever.cpp b/media/jni/android_media_MediaMetadataRetriever.cpp
index 59fb6d6..f4e940d 100644
--- a/media/jni/android_media_MediaMetadataRetriever.cpp
+++ b/media/jni/android_media_MediaMetadataRetriever.cpp
@@ -467,7 +467,7 @@
 }
 
 // JNI mapping between Java methods and native methods
-static JNINativeMethod nativeMethods[] = {
+static const JNINativeMethod nativeMethods[] = {
         {
             "_setDataSource",
             "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;[Ljava/lang/String;)V",
diff --git a/media/jni/android_media_MediaMuxer.cpp b/media/jni/android_media_MediaMuxer.cpp
index ecb2ac8..216624e 100644
--- a/media/jni/android_media_MediaMuxer.cpp
+++ b/media/jni/android_media_MediaMuxer.cpp
@@ -219,7 +219,7 @@
     }
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
 
     { "nativeAddTrack", "(J[Ljava/lang/String;[Ljava/lang/Object;)I",
         (void *)android_media_MediaMuxer_addTrack },
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index d8041f4..be36729 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -1033,7 +1033,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {
         "nativeSetDataSource",
         "(Landroid/os/IBinder;Ljava/lang/String;[Ljava/lang/String;"
diff --git a/media/jni/android_media_MediaProfiles.cpp b/media/jni/android_media_MediaProfiles.cpp
index ca9db91..5800043 100644
--- a/media/jni/android_media_MediaProfiles.cpp
+++ b/media/jni/android_media_MediaProfiles.cpp
@@ -301,7 +301,7 @@
     }
     return static_cast<jint>(levels[index]);
 }
-static JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
+static const JNINativeMethod gMethodsForEncoderCapabilitiesClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_file_formats",            "()I",                    (void *)android_media_MediaProfiles_native_get_num_file_formats},
     {"native_get_file_format",                 "(I)I",                   (void *)android_media_MediaProfiles_native_get_file_format},
@@ -315,7 +315,7 @@
                                                                          (void *)android_media_MediaProfiles_native_get_audio_encoder_cap},
 };
 
-static JNINativeMethod gMethodsForCamcorderProfileClass[] = {
+static const JNINativeMethod gMethodsForCamcorderProfileClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_camcorder_profile",           "(II)Landroid/media/CamcorderProfile;",
                                                                          (void *)android_media_MediaProfiles_native_get_camcorder_profile},
@@ -323,7 +323,7 @@
                                                                          (void *)android_media_MediaProfiles_native_has_camcorder_profile},
 };
 
-static JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
+static const JNINativeMethod gMethodsForDecoderCapabilitiesClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_video_decoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_video_decoders},
     {"native_get_num_audio_decoders",          "()I",                    (void *)android_media_MediaProfiles_native_get_num_audio_decoders},
@@ -331,7 +331,7 @@
     {"native_get_audio_decoder_type",          "(I)I",                   (void *)android_media_MediaProfiles_native_get_audio_decoder_type},
 };
 
-static JNINativeMethod gMethodsForCameraProfileClass[] = {
+static const JNINativeMethod gMethodsForCameraProfileClass[] = {
     {"native_init",                            "()V",                    (void *)android_media_MediaProfiles_native_init},
     {"native_get_num_image_encoding_quality_levels",
                                                "(I)I",                   (void *)android_media_MediaProfiles_native_get_num_image_encoding_quality_levels},
diff --git a/media/jni/android_media_MediaRecorder.cpp b/media/jni/android_media_MediaRecorder.cpp
index f60af63..e05b348 100644
--- a/media/jni/android_media_MediaRecorder.cpp
+++ b/media/jni/android_media_MediaRecorder.cpp
@@ -510,7 +510,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"setCamera",            "(Landroid/hardware/Camera;)V",    (void *)android_media_MediaRecorder_setCamera},
     {"setVideoSource",       "(I)V",                            (void *)android_media_MediaRecorder_setVideoSource},
     {"setAudioSource",       "(I)V",                            (void *)android_media_MediaRecorder_setAudioSource},
diff --git a/media/jni/android_media_MediaScanner.cpp b/media/jni/android_media_MediaScanner.cpp
index 1a9384e..0f3c61f 100644
--- a/media/jni/android_media_MediaScanner.cpp
+++ b/media/jni/android_media_MediaScanner.cpp
@@ -412,7 +412,7 @@
     setNativeScanner_l(env, thiz, 0);
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {
         "processDirectory",
         "(Ljava/lang/String;Landroid/media/MediaScannerClient;)V",
diff --git a/media/jni/android_media_ResampleInputStream.cpp b/media/jni/android_media_ResampleInputStream.cpp
index 1549a30..d06baa5 100644
--- a/media/jni/android_media_ResampleInputStream.cpp
+++ b/media/jni/android_media_ResampleInputStream.cpp
@@ -107,7 +107,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"fir21", "([BI[BII)V", (void*)android_media_ResampleInputStream_fir21},
 };
 
diff --git a/media/jni/android_mtp_MtpDatabase.cpp b/media/jni/android_mtp_MtpDatabase.cpp
index 713f28c..ec2f98a 100644
--- a/media/jni/android_mtp_MtpDatabase.cpp
+++ b/media/jni/android_mtp_MtpDatabase.cpp
@@ -1173,12 +1173,12 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMtpDatabaseMethods[] = {
+static const JNINativeMethod gMtpDatabaseMethods[] = {
     {"native_setup",            "()V",  (void *)android_mtp_MtpDatabase_setup},
     {"native_finalize",         "()V",  (void *)android_mtp_MtpDatabase_finalize},
 };
 
-static JNINativeMethod gMtpPropertyGroupMethods[] = {
+static const JNINativeMethod gMtpPropertyGroupMethods[] = {
     {"format_date_time",        "(J)Ljava/lang/String;",
                                         (void *)android_mtp_MtpPropertyGroup_format_date_time},
 };
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 2a46ee7..3f4d183 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -46,10 +46,14 @@
 jclass clazz_deviceInfo;
 jclass clazz_storageInfo;
 jclass clazz_objectInfo;
+jclass clazz_event;
+jclass clazz_io_exception;
+jclass clazz_operation_canceled_exception;
 
 jmethodID constructor_deviceInfo;
 jmethodID constructor_storageInfo;
 jmethodID constructor_objectInfo;
+jmethodID constructor_event;
 
 // MtpDeviceInfo fields
 static jfieldID field_deviceInfo_manufacturer;
@@ -86,6 +90,9 @@
 static jfieldID field_objectInfo_dateModified;
 static jfieldID field_objectInfo_keywords;
 
+// MtpEvent fields
+static jfieldID field_event_eventCode;
+
 MtpDevice* get_device_from_object(JNIEnv* env, jobject javaDevice)
 {
     return (MtpDevice*)env->GetLongField(javaDevice, field_context);
@@ -488,9 +495,45 @@
     return result;
 }
 
+static jint android_mtp_MtpDevice_submit_event_request(JNIEnv *env, jobject thiz)
+{
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        env->ThrowNew(clazz_io_exception, "");
+        return -1;
+    }
+    return device->submitEventRequest();
+}
+
+static jobject android_mtp_MtpDevice_reap_event_request(JNIEnv *env, jobject thiz, jint seq)
+{
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        env->ThrowNew(clazz_io_exception, "");
+        return NULL;
+    }
+    const int eventCode = device->reapEventRequest(seq);
+    if (eventCode <= 0) {
+        env->ThrowNew(clazz_operation_canceled_exception, "");
+        return NULL;
+    }
+    jobject result = env->NewObject(clazz_event, constructor_event);
+    env->SetIntField(result, field_event_eventCode, eventCode);
+    return result;
+}
+
+static void android_mtp_MtpDevice_discard_event_request(JNIEnv *env, jobject thiz, jint seq)
+{
+    MtpDevice* const device = get_device_from_object(env, thiz);
+    if (!device) {
+        return;
+    }
+    device->discardEventRequest(seq);
+}
+
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_open",             "(Ljava/lang/String;I)Z",
                                         (void *)android_mtp_MtpDevice_open},
     {"native_close",            "()V",  (void *)android_mtp_MtpDevice_close},
@@ -513,7 +556,11 @@
     {"native_import_file",      "(II)Z",(void *)android_mtp_MtpDevice_import_file_to_fd},
     {"native_send_object",      "(III)Z",(void *)android_mtp_MtpDevice_send_object},
     {"native_send_object_info", "(Landroid/mtp/MtpObjectInfo;)Landroid/mtp/MtpObjectInfo;",
-                                        (void *)android_mtp_MtpDevice_send_object_info}
+                                        (void *)android_mtp_MtpDevice_send_object_info},
+    {"native_submit_event_request",  "()I", (void *)android_mtp_MtpDevice_submit_event_request},
+    {"native_reap_event_request",   "(I)Landroid/mtp/MtpEvent;",
+                                            (void *)android_mtp_MtpDevice_reap_event_request},
+    {"native_discard_event_request", "(I)V", (void *)android_mtp_MtpDevice_discard_event_request},
 };
 
 int register_android_mtp_MtpDevice(JNIEnv *env)
@@ -703,6 +750,23 @@
     }
     clazz_objectInfo = (jclass)env->NewGlobalRef(clazz);
 
+    clazz = env->FindClass("android/mtp/MtpEvent");
+    if (clazz == NULL) {
+        ALOGE("Can't find android/mtp/MtpEvent");
+        return -1;
+    }
+    constructor_event = env->GetMethodID(clazz, "<init>", "()V");
+    if (constructor_event == NULL) {
+        ALOGE("Can't find android/mtp/MtpEvent constructor");
+        return -1;
+    }
+    field_event_eventCode = env->GetFieldID(clazz, "mEventCode", "I");
+    if (field_event_eventCode == NULL) {
+        ALOGE("Can't find MtpObjectInfo.mEventCode");
+        return -1;
+    }
+    clazz_event = (jclass)env->NewGlobalRef(clazz);
+
     clazz = env->FindClass("android/mtp/MtpDevice");
     if (clazz == NULL) {
         ALOGE("Can't find android/mtp/MtpDevice");
@@ -713,6 +777,18 @@
         ALOGE("Can't find MtpDevice.mNativeContext");
         return -1;
     }
+    clazz = env->FindClass("java/io/IOException");
+    if (clazz == NULL) {
+        ALOGE("Can't find java.io.IOException");
+        return -1;
+    }
+    clazz_io_exception = (jclass)env->NewGlobalRef(clazz);
+    clazz = env->FindClass("android/os/OperationCanceledException");
+    if (clazz == NULL) {
+        ALOGE("Can't find android.os.OperationCanceledException");
+        return -1;
+    }
+    clazz_operation_canceled_exception = (jclass)env->NewGlobalRef(clazz);
 
     return AndroidRuntime::registerNativeMethods(env,
                 "android/mtp/MtpDevice", gMethods, NELEM(gMethods));
diff --git a/media/jni/android_mtp_MtpServer.cpp b/media/jni/android_mtp_MtpServer.cpp
index 2ce2a90..d13187c 100644
--- a/media/jni/android_mtp_MtpServer.cpp
+++ b/media/jni/android_mtp_MtpServer.cpp
@@ -179,7 +179,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_setup",                "(Landroid/mtp/MtpDatabase;Z)V",
                                             (void *)android_mtp_MtpServer_setup},
     {"native_run",                  "()V",  (void *)android_mtp_MtpServer_run},
diff --git a/media/jni/audioeffect/android_media_AudioEffect.cpp b/media/jni/audioeffect/android_media_AudioEffect.cpp
index aba4bbe..fa69135 100644
--- a/media/jni/audioeffect/android_media_AudioEffect.cpp
+++ b/media/jni/audioeffect/android_media_AudioEffect.cpp
@@ -879,7 +879,7 @@
 // ----------------------------------------------------------------------------
 
 // Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_init",          "()V",      (void *)android_media_AudioEffect_native_init},
     {"native_setup",         "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I",
                                          (void *)android_media_AudioEffect_native_setup},
diff --git a/media/jni/audioeffect/android_media_Visualizer.cpp b/media/jni/audioeffect/android_media_Visualizer.cpp
index 0557019..3d3adba 100644
--- a/media/jni/audioeffect/android_media_Visualizer.cpp
+++ b/media/jni/audioeffect/android_media_Visualizer.cpp
@@ -677,7 +677,7 @@
 // ----------------------------------------------------------------------------
 
 // Dalvik VM type signatures
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"native_init",            "()V",     (void *)android_media_visualizer_native_init},
     {"native_setup",           "(Ljava/lang/Object;I[ILjava/lang/String;)I",
                                           (void *)android_media_visualizer_native_setup},
diff --git a/native/graphics/jni/Android.mk b/native/graphics/jni/Android.mk
index 1b684bb..175f730 100644
--- a/native/graphics/jni/Android.mk
+++ b/native/graphics/jni/Android.mk
@@ -31,7 +31,7 @@
 
 LOCAL_CFLAGS += -Wall -Werror -Wunused -Wunreachable-code
 
-# TODO: This is to work around b/19059885. Remove after root cause is fixed
+# TODO: This is to work around b/24465209. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm := -Wl,--hash-style=both
 
 include $(BUILD_SHARED_LIBRARY)
diff --git a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
index 969ec599..6a7dbbd 100644
--- a/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
+++ b/packages/BackupRestoreConfirmation/res/values-ro/strings.xml
@@ -18,10 +18,10 @@
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="backup_confirm_title" msgid="827563724209303345">"Copiere de rezervă completă"</string>
     <string name="restore_confirm_title" msgid="5469365809567486602">"Restabilire completă"</string>
-    <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operaţiunea să continue."</string>
+    <string name="backup_confirm_text" msgid="1878021282758896593">"S-a solicitat crearea unei copii de rezervă complete a tuturor datelor pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu aţi solicitat dvs. copierea de rezervă, nu permiteți ca operațiunea să continue."</string>
     <string name="allow_backup_button_label" msgid="4217228747769644068">"Creaţi copii de rezervă pentru datele dvs."</string>
     <string name="deny_backup_button_label" msgid="6009119115581097708">"Nu creaţi copii de rezervă"</string>
-    <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operaţiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
+    <string name="restore_confirm_text" msgid="7499866728030461776">"S-a solicitat o restabilire completă a tuturor datelor de pe un computer desktop conectat. Doriți să permiteți acest lucru?\n\nDacă nu dvs. aţi solicitat această restabilire, nu permiteți continuarea operațiunii. Acest proces va înlocui toate datele existente în prezent pe dispozitiv!"</string>
     <string name="allow_restore_button_label" msgid="3081286752277127827">"Restabiliţi datele dvs."</string>
     <string name="deny_restore_button_label" msgid="1724367334453104378">"Nu restabiliţi"</string>
     <string name="current_password_text" msgid="8268189555578298067">"Introduceţi mai jos parola actuală pentru copia de rezervă:"</string>
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index 0fe5509..abb464e 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -76,8 +76,9 @@
         String server = Settings.Global.getString(getContentResolver(), "captive_portal_server");
         if (server == null) server = DEFAULT_SERVER;
         mCm = ConnectivityManager.from(this);
+        String url = getIntent().getStringExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL);
         try {
-            mURL = new URL("http", server, "/generate_204");
+            mURL = url != null ? new URL(url) : new URL("http", server, "/generate_204");
         } catch (MalformedURLException e) {
             // System misconfigured, bail out in a way that at least provides network access.
             Log.e(TAG, "Invalid captive portal URL, server=" + server);
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index 97bc8fd..295cb80 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -3,6 +3,7 @@
 
     <uses-permission android:name="android.permission.MANAGE_DOCUMENTS" />
     <uses-permission android:name="android.permission.REMOVE_TASKS" />
+    <uses-permission android:name="android.permission.REORDER_TASKS" />
 
     <application
         android:name=".DocumentsApplication"
@@ -35,11 +36,6 @@
                 <action android:name="android.intent.action.OPEN_DOCUMENT_TREE" />
                 <category android:name="android.intent.category.DEFAULT" />
             </intent-filter>
-            <intent-filter>
-                <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
-                <category android:name="android.intent.category.DEFAULT" />
-                <data android:mimeType="vnd.android.document/root" />
-            </intent-filter>
         </activity>
 
         <activity
@@ -54,8 +50,8 @@
         </activity>
 
         <activity
-            android:name=".FilesActivity"
-            android:theme="@style/FilesTheme"
+            android:name=".LauncherActivity"
+            android:theme="@android:style/Theme.NoDisplay"
             android:icon="@drawable/ic_files_app"
             android:label="@string/files_label"
             android:enabled="@bool/productivity_device">
@@ -65,6 +61,22 @@
             </intent-filter>
         </activity>
 
+        <activity
+            android:name=".FilesActivity"
+            android:theme="@style/FilesTheme"
+            android:icon="@drawable/ic_files_app"
+            android:label="@string/files_label"
+            android:documentLaunchMode="intoExisting">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+            </intent-filter>
+            <intent-filter>
+                <action android:name="android.provider.action.BROWSE_DOCUMENT_ROOT" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <data android:mimeType="vnd.android.document/root" />
+            </intent-filter>
+        </activity>
+
         <provider
             android:name=".RecentsProvider"
             android:authorities="com.android.documentsui.recents"
diff --git a/packages/DocumentsUI/res/layout/drawer_layout.xml b/packages/DocumentsUI/res/layout/drawer_layout.xml
index dec4e92..0dac0d5 100644
--- a/packages/DocumentsUI/res/layout/drawer_layout.xml
+++ b/packages/DocumentsUI/res/layout/drawer_layout.xml
@@ -14,62 +14,71 @@
      limitations under the License.
 -->
 
-<android.support.v4.widget.DrawerLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/drawer_layout"
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+     floating action buttons) to operate correctly. -->
+<android.support.design.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:id="@+id/coordinator_layout">
 
-    <LinearLayout
+    <android.support.v4.widget.DrawerLayout
+        android:id="@+id/drawer_layout"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:orientation="vertical">
+        android:layout_height="match_parent">
 
-        <com.android.documentsui.DocumentsToolBar
-            android:id="@+id/toolbar"
+        <LinearLayout
             android:layout_width="match_parent"
-            android:layout_height="?android:attr/actionBarSize"
-            android:background="?android:attr/colorPrimary"
-            android:elevation="8dp"
-            android:theme="?actionBarTheme"
-            android:popupTheme="?actionBarPopupTheme">
+            android:layout_height="match_parent"
+            android:orientation="vertical">
 
-            <Spinner
-                android:id="@+id/stack"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_marginStart="4dp"
-                android:overlapAnchor="true" />
+            <com.android.documentsui.DocumentsToolBar
+                android:id="@+id/toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="?android:attr/actionBarSize"
+                android:background="?android:attr/colorPrimary"
+                android:elevation="8dp"
+                android:theme="?actionBarTheme"
+                android:popupTheme="?actionBarPopupTheme">
 
-        </com.android.documentsui.DocumentsToolBar>
+                <Spinner
+                    android:id="@+id/stack"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_marginStart="4dp"
+                    android:overlapAnchor="true" />
 
-        <include layout="@layout/directory_cluster"/>
+            </com.android.documentsui.DocumentsToolBar>
 
-    </LinearLayout>
+            <include layout="@layout/directory_cluster"/>
 
-    <LinearLayout
-        android:id="@+id/drawer_roots"
-        android:layout_width="256dp"
-        android:layout_height="match_parent"
-        android:layout_gravity="start"
-        android:orientation="vertical"
-        android:elevation="16dp"
-        android:background="@*android:color/white">
+        </LinearLayout>
 
-        <Toolbar
-            android:id="@+id/roots_toolbar"
-            android:layout_width="match_parent"
-            android:layout_height="?android:attr/actionBarSize"
-            android:background="?android:attr/colorPrimary"
-            android:elevation="8dp"
-            android:theme="?actionBarTheme"
-            android:popupTheme="?actionBarPopupTheme" />
+        <LinearLayout
+            android:id="@+id/drawer_roots"
+            android:layout_width="256dp"
+            android:layout_height="match_parent"
+            android:layout_gravity="start"
+            android:orientation="vertical"
+            android:elevation="16dp"
+            android:background="@*android:color/white">
 
-        <FrameLayout
-            android:id="@+id/container_roots"
-            android:layout_width="match_parent"
-            android:layout_height="0dp"
-            android:layout_weight="1" />
+            <Toolbar
+                android:id="@+id/roots_toolbar"
+                android:layout_width="match_parent"
+                android:layout_height="?android:attr/actionBarSize"
+                android:background="?android:attr/colorPrimary"
+                android:elevation="8dp"
+                android:theme="?actionBarTheme"
+                android:popupTheme="?actionBarPopupTheme" />
 
-    </LinearLayout>
+            <FrameLayout
+                android:id="@+id/container_roots"
+                android:layout_width="match_parent"
+                android:layout_height="0dp"
+                android:layout_weight="1" />
 
-</android.support.v4.widget.DrawerLayout>
+        </LinearLayout>
+
+    </android.support.v4.widget.DrawerLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/packages/DocumentsUI/res/layout/fixed_layout.xml b/packages/DocumentsUI/res/layout/fixed_layout.xml
index eba9af4..403c667 100644
--- a/packages/DocumentsUI/res/layout/fixed_layout.xml
+++ b/packages/DocumentsUI/res/layout/fixed_layout.xml
@@ -14,49 +14,59 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+     floating action buttons) to operate correctly. -->
+<android.support.design.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:id="@+id/coordinator_layout">
 
-    <com.android.documentsui.DocumentsToolBar
-        android:id="@+id/toolbar"
+    <LinearLayout 
         android:layout_width="match_parent"
-        android:layout_height="?android:attr/actionBarSize"
-        android:background="?android:attr/colorPrimary"
-        android:elevation="8dp"
-        android:theme="?actionBarTheme"
-        android:popupTheme="?actionBarPopupTheme">
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-        <Spinner
-            android:id="@+id/stack"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="4dp"
-            android:overlapAnchor="true" />
-
-    </com.android.documentsui.DocumentsToolBar>
-
-    <LinearLayout
-        android:layout_width="match_parent"
-        android:layout_height="0dp"
-        android:layout_weight="1"
-        android:orientation="horizontal"
-        android:baselineAligned="false"
-        android:divider="?android:attr/dividerVertical"
-        android:showDividers="middle">
-
-        <FrameLayout
-            android:id="@+id/container_roots"
-            android:layout_width="256dp"
-            android:layout_height="match_parent" />
-
-        <include layout="@layout/directory_cluster"
-            android:layout_width="0dp"
-            android:layout_weight="1"
+        <com.android.documentsui.DocumentsToolBar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?android:attr/actionBarSize"
+            android:background="?android:attr/colorPrimary"
             android:elevation="8dp"
-            android:background="@color/material_grey_50" />
+            android:theme="?actionBarTheme"
+            android:popupTheme="?actionBarPopupTheme">
+
+            <Spinner
+                android:id="@+id/stack"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="4dp"
+                android:overlapAnchor="true" />
+
+        </com.android.documentsui.DocumentsToolBar>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="0dp"
+            android:layout_weight="1"
+            android:orientation="horizontal"
+            android:baselineAligned="false"
+            android:divider="?android:attr/dividerVertical"
+            android:showDividers="middle">
+
+            <FrameLayout
+                android:id="@+id/container_roots"
+                android:layout_width="256dp"
+                android:layout_height="match_parent" />
+
+            <include layout="@layout/directory_cluster"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:elevation="8dp"
+                android:background="@color/material_grey_50" />
+
+        </LinearLayout>
 
     </LinearLayout>
 
-</LinearLayout>
+</android.support.design.widget.CoordinatorLayout>
diff --git a/packages/DocumentsUI/res/layout/fragment_directory.xml b/packages/DocumentsUI/res/layout/fragment_directory.xml
index b02349a..45cb34d 100644
--- a/packages/DocumentsUI/res/layout/fragment_directory.xml
+++ b/packages/DocumentsUI/res/layout/fragment_directory.xml
@@ -17,61 +17,70 @@
 <com.android.documentsui.DirectoryView xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="@color/material_grey_50">
+    android:background="@color/material_grey_50"
+    android:orientation="vertical"
+    android:animateLayoutChanges="true">
 
-    <TextView
-        android:id="@android:id/empty"
+    <ProgressBar
+        android:id="@+id/progressbar"
         android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:gravity="center"
-        android:text="@string/empty"
-        android:visibility="gone"
-        style="@android:style/TextAppearance.Material.Subhead" />
+        android:layout_height="wrap_content"
+        android:indeterminate="true"
+        style="@style/TrimmedHorizontalProgressBar"
+        android:visibility="gone"/>
+  
+    <FrameLayout
+        android:id="@+id/container_message_bar"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:elevation="8dp"
+        android:background="@color/material_grey_50"
+        android:visibility="gone"/>
 
+    <!-- The empty directory view -->
     <LinearLayout
-        android:id="@+id/content"
+        android:id="@android:id/empty"
+        android:gravity="center"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:orientation="vertical"
-        android:animateLayoutChanges="true">
-
-        <ProgressBar
-            android:id="@+id/progressbar"
-            android:layout_width="match_parent"
+        android:visibility="gone">
+        
+        <TextView
+            android:id="@+id/message"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:indeterminate="true"
-            style="@style/TrimmedHorizontalProgressBar"
-            android:visibility="gone"/>
+            android:text="@string/empty"
+            style="@android:style/TextAppearance.Material.Subhead" />
 
-        <FrameLayout
-            android:id="@+id/container_message_bar"
-            android:layout_width="match_parent"
+         <Button
+            android:id="@+id/button_retry"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:elevation="8dp"
-            android:background="@color/material_grey_50"
-            android:visibility="gone"/>
-
-        <!-- This FrameLayout works around b/24189541 -->
-        <FrameLayout
-            android:layout_width="match_parent"
-            android:layout_height="match_parent">
-
-            <android.support.v7.widget.RecyclerView
-                android:id="@+id/recyclerView"
-                android:scrollbars="vertical"
-                android:layout_width="match_parent"
-                android:layout_height="match_parent"
-                android:paddingStart="@dimen/grid_padding_horiz"
-                android:paddingEnd="@dimen/grid_padding_horiz"
-                android:paddingTop="@dimen/grid_padding_vert"
-                android:paddingBottom="@dimen/grid_padding_vert"
-                android:clipToPadding="false"
-                android:scrollbarStyle="outsideOverlay"
-                android:drawSelectorOnTop="true"
-                android:background="@color/directory_background" />
-
-        </FrameLayout>
-
+            android:text="@string/button_retry"
+            style="?android:attr/buttonBarPositiveButtonStyle" />
+        
     </LinearLayout>
+    
+    <!-- This FrameLayout works around b/24189541 -->
+    <FrameLayout
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+
+        <android.support.v7.widget.RecyclerView
+            android:id="@+id/recyclerView"
+            android:scrollbars="vertical"
+            android:layout_width="match_parent"
+            android:layout_height="match_parent"
+            android:paddingStart="@dimen/grid_padding_horiz"
+            android:paddingEnd="@dimen/grid_padding_horiz"
+            android:paddingTop="@dimen/grid_padding_vert"
+            android:paddingBottom="@dimen/grid_padding_vert"
+            android:clipToPadding="false"
+            android:scrollbarStyle="outsideOverlay"
+            android:drawSelectorOnTop="true"
+            android:background="@color/directory_background" />
+
+    </FrameLayout>
 
 </com.android.documentsui.DirectoryView>
diff --git a/packages/DocumentsUI/res/layout/single_pane_layout.xml b/packages/DocumentsUI/res/layout/single_pane_layout.xml
index 20c3232..c5a5745 100644
--- a/packages/DocumentsUI/res/layout/single_pane_layout.xml
+++ b/packages/DocumentsUI/res/layout/single_pane_layout.xml
@@ -14,29 +14,39 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<!-- CoordinatorLayout is necessary for various components (e.g. Snackbars, and
+     floating action buttons) to operate correctly. -->
+<android.support.design.widget.CoordinatorLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:orientation="vertical">
+    android:id="@+id/coordinator_layout">
 
-    <com.android.documentsui.DocumentsToolBar
-        android:id="@+id/toolbar"
+    <LinearLayout
         android:layout_width="match_parent"
-        android:layout_height="?android:attr/actionBarSize"
-        android:background="?android:attr/colorPrimary"
-        android:elevation="8dp"
-        android:theme="?actionBarTheme"
-        android:popupTheme="?actionBarPopupTheme">
+        android:layout_height="match_parent"
+        android:orientation="vertical">
 
-        <Spinner
-            android:id="@+id/stack"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginStart="4dp"
-            android:overlapAnchor="true" />
+        <com.android.documentsui.DocumentsToolBar
+            android:id="@+id/toolbar"
+            android:layout_width="match_parent"
+            android:layout_height="?android:attr/actionBarSize"
+            android:background="?android:attr/colorPrimary"
+            android:elevation="8dp"
+            android:theme="?actionBarTheme"
+            android:popupTheme="?actionBarPopupTheme">
 
-    </com.android.documentsui.DocumentsToolBar>
+            <Spinner
+                android:id="@+id/stack"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_marginStart="4dp"
+                android:overlapAnchor="true" />
 
-    <include layout="@layout/directory_cluster"/>
+        </com.android.documentsui.DocumentsToolBar>
 
-</LinearLayout>
+        <include layout="@layout/directory_cluster"/>
+
+    </LinearLayout>
+
+</android.support.design.widget.CoordinatorLayout>
diff --git a/packages/DocumentsUI/res/menu/activity.xml b/packages/DocumentsUI/res/menu/activity.xml
index 7df152f..673a254 100644
--- a/packages/DocumentsUI/res/menu/activity.xml
+++ b/packages/DocumentsUI/res/menu/activity.xml
@@ -26,6 +26,7 @@
         android:id="@+id/menu_create_dir"
         android:title="@string/menu_create_dir"
         android:icon="@drawable/ic_menu_new_folder"
+        android:alphabeticShortcut="e"
         android:showAsAction="always"
         android:visible="false" />
     <item
@@ -56,11 +57,18 @@
         android:icon="@drawable/ic_menu_view_list"
         android:showAsAction="never" />
     <item
+        android:id="@+id/menu_new_window"
+        android:title="@string/menu_new_window"
+        android:alphabeticShortcut="n"
+        android:showAsAction="never"
+        android:visible="false" />
+    <item
         android:id="@+id/menu_paste_from_clipboard"
         android:title="@string/menu_paste_from_clipboard"
         android:alphabeticShortcut="v"
         android:showAsAction="never"
         android:visible="false" />
+    <!-- Copy action is defined in mode_directory.xml -->
     <item
         android:id="@+id/menu_advanced"
         android:showAsAction="never"
diff --git a/packages/DocumentsUI/res/values-af/strings.xml b/packages/DocumentsUI/res/values-af/strings.xml
index 0053f22..c2b6dbc 100644
--- a/packages/DocumentsUI/res/values-af/strings.xml
+++ b/packages/DocumentsUI/res/values-af/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Kies"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopieer"</string>
     <string name="button_move" msgid="2202666023104202232">"Skuif"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Maak toe"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Probeer weer"</string>
     <string name="sort_name" msgid="9183560467917256779">"Volgens naam"</string>
     <string name="sort_date" msgid="586080032956151448">"Volgens datum gewysig"</string>
     <string name="sort_size" msgid="3350681319735474741">"Volgens grootte"</string>
diff --git a/packages/DocumentsUI/res/values-am/strings.xml b/packages/DocumentsUI/res/values-am/strings.xml
index eb88830..b82fa93 100644
--- a/packages/DocumentsUI/res/values-am/strings.xml
+++ b/packages/DocumentsUI/res/values-am/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"ምረጥ"</string>
     <string name="button_copy" msgid="8706475544635021302">"ቅዳ"</string>
     <string name="button_move" msgid="2202666023104202232">"አንቀሳቀስ"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"አሰናብት"</string>
+    <string name="button_retry" msgid="4392027584153752797">"እንደገና ይሞክሩ"</string>
     <string name="sort_name" msgid="9183560467917256779">"በስም"</string>
     <string name="sort_date" msgid="586080032956151448">"በተለወጠበት ቀን"</string>
     <string name="sort_size" msgid="3350681319735474741">"በመጠን"</string>
diff --git a/packages/DocumentsUI/res/values-ar/strings.xml b/packages/DocumentsUI/res/values-ar/strings.xml
index bf464b6..c7c9ef2 100644
--- a/packages/DocumentsUI/res/values-ar/strings.xml
+++ b/packages/DocumentsUI/res/values-ar/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"تحديد"</string>
     <string name="button_copy" msgid="8706475544635021302">"نسخ"</string>
     <string name="button_move" msgid="2202666023104202232">"نقل"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"إزالة"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"بحسب الاسم"</string>
     <string name="sort_date" msgid="586080032956151448">"بحسب تاريخ التعديل"</string>
     <string name="sort_size" msgid="3350681319735474741">"بحسب الحجم"</string>
diff --git a/packages/DocumentsUI/res/values-az-rAZ/strings.xml b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
index 0bd01a5..8c79ceb 100644
--- a/packages/DocumentsUI/res/values-az-rAZ/strings.xml
+++ b/packages/DocumentsUI/res/values-az-rAZ/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Seçin"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string>
     <string name="button_move" msgid="2202666023104202232">"Köçürün"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Rədd edin"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Ad üzrə"</string>
     <string name="sort_date" msgid="586080032956151448">"Tarix üzrə dəyişmiş"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ölçü üzrə"</string>
diff --git a/packages/DocumentsUI/res/values-bg/strings.xml b/packages/DocumentsUI/res/values-bg/strings.xml
index 669145e..fdf57d0 100644
--- a/packages/DocumentsUI/res/values-bg/strings.xml
+++ b/packages/DocumentsUI/res/values-bg/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Избиране"</string>
     <string name="button_copy" msgid="8706475544635021302">"Копиране"</string>
     <string name="button_move" msgid="2202666023104202232">"Преместване"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Отхвърляне"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"По име"</string>
     <string name="sort_date" msgid="586080032956151448">"По дата на промяната"</string>
     <string name="sort_size" msgid="3350681319735474741">"По размер"</string>
diff --git a/packages/DocumentsUI/res/values-bn-rBD/strings.xml b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
index 240ba6c..7caf57f 100644
--- a/packages/DocumentsUI/res/values-bn-rBD/strings.xml
+++ b/packages/DocumentsUI/res/values-bn-rBD/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"নির্বাচন করুন"</string>
     <string name="button_copy" msgid="8706475544635021302">"অনুলিপি করুন"</string>
     <string name="button_move" msgid="2202666023104202232">"সরান"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"খারিজ করুন"</string>
+    <string name="button_retry" msgid="4392027584153752797">"আবার চেষ্টা করুন"</string>
     <string name="sort_name" msgid="9183560467917256779">"নামের দ্বারা"</string>
     <string name="sort_date" msgid="586080032956151448">"পরিবর্তনের তারিখ দ্বারা"</string>
     <string name="sort_size" msgid="3350681319735474741">"আকার অনুযায়ী"</string>
diff --git a/packages/DocumentsUI/res/values-ca/strings.xml b/packages/DocumentsUI/res/values-ca/strings.xml
index 30accda..ab365ce 100644
--- a/packages/DocumentsUI/res/values-ca/strings.xml
+++ b/packages/DocumentsUI/res/values-ca/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Selecciona"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copia"</string>
     <string name="button_move" msgid="2202666023104202232">"Desplaça"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Per nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Per data de modificació"</string>
     <string name="sort_size" msgid="3350681319735474741">"Per mida"</string>
diff --git a/packages/DocumentsUI/res/values-cs/strings.xml b/packages/DocumentsUI/res/values-cs/strings.xml
index cb1d973..62b313c 100644
--- a/packages/DocumentsUI/res/values-cs/strings.xml
+++ b/packages/DocumentsUI/res/values-cs/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Vybrat"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopírovat"</string>
     <string name="button_move" msgid="2202666023104202232">"Přesunout"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Zavřít"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Zkusit znovu"</string>
     <string name="sort_name" msgid="9183560467917256779">"Podle názvu"</string>
     <string name="sort_date" msgid="586080032956151448">"Podle data úpravy"</string>
     <string name="sort_size" msgid="3350681319735474741">"Podle velikosti"</string>
diff --git a/packages/DocumentsUI/res/values-da/strings.xml b/packages/DocumentsUI/res/values-da/strings.xml
index f12737c..c3d7cdd 100644
--- a/packages/DocumentsUI/res/values-da/strings.xml
+++ b/packages/DocumentsUI/res/values-da/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Vælg"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiér"</string>
     <string name="button_move" msgid="2202666023104202232">"Flyt"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Luk"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Prøv igen"</string>
     <string name="sort_name" msgid="9183560467917256779">"Efter navn"</string>
     <string name="sort_date" msgid="586080032956151448">"Efter ændringsdato"</string>
     <string name="sort_size" msgid="3350681319735474741">"Efter størrelse"</string>
diff --git a/packages/DocumentsUI/res/values-de/strings.xml b/packages/DocumentsUI/res/values-de/strings.xml
index a7be4db..f88b5c4 100644
--- a/packages/DocumentsUI/res/values-de/strings.xml
+++ b/packages/DocumentsUI/res/values-de/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Auswählen"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopieren"</string>
     <string name="button_move" msgid="2202666023104202232">"Verschieben"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Schließen"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Erneut versuchen"</string>
     <string name="sort_name" msgid="9183560467917256779">"Nach Name"</string>
     <string name="sort_date" msgid="586080032956151448">"Nach Änderungsdatum"</string>
     <string name="sort_size" msgid="3350681319735474741">"Nach Größe"</string>
diff --git a/packages/DocumentsUI/res/values-el/strings.xml b/packages/DocumentsUI/res/values-el/strings.xml
index 82155a8..dcca46c 100644
--- a/packages/DocumentsUI/res/values-el/strings.xml
+++ b/packages/DocumentsUI/res/values-el/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Επιλογή"</string>
     <string name="button_copy" msgid="8706475544635021302">"Αντιγραφή"</string>
     <string name="button_move" msgid="2202666023104202232">"Μετακίνηση"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Παράβλεψη"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Δοκιμάστε ξανά"</string>
     <string name="sort_name" msgid="9183560467917256779">"Κατά όνομα"</string>
     <string name="sort_date" msgid="586080032956151448">"Κατά ημερομηνία τροποποίησης"</string>
     <string name="sort_size" msgid="3350681319735474741">"Κατά μέγεθος"</string>
diff --git a/packages/DocumentsUI/res/values-en-rAU/strings.xml b/packages/DocumentsUI/res/values-en-rAU/strings.xml
index c609047..26fd30f 100644
--- a/packages/DocumentsUI/res/values-en-rAU/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rAU/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"select"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copy"</string>
     <string name="button_move" msgid="2202666023104202232">"Move"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Try again"</string>
     <string name="sort_name" msgid="9183560467917256779">"By name"</string>
     <string name="sort_date" msgid="586080032956151448">"By date modified"</string>
     <string name="sort_size" msgid="3350681319735474741">"By size"</string>
diff --git a/packages/DocumentsUI/res/values-en-rGB/strings.xml b/packages/DocumentsUI/res/values-en-rGB/strings.xml
index c609047..26fd30f 100644
--- a/packages/DocumentsUI/res/values-en-rGB/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rGB/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"select"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copy"</string>
     <string name="button_move" msgid="2202666023104202232">"Move"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Try again"</string>
     <string name="sort_name" msgid="9183560467917256779">"By name"</string>
     <string name="sort_date" msgid="586080032956151448">"By date modified"</string>
     <string name="sort_size" msgid="3350681319735474741">"By size"</string>
diff --git a/packages/DocumentsUI/res/values-en-rIN/strings.xml b/packages/DocumentsUI/res/values-en-rIN/strings.xml
index c609047..26fd30f 100644
--- a/packages/DocumentsUI/res/values-en-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-en-rIN/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"select"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copy"</string>
     <string name="button_move" msgid="2202666023104202232">"Move"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Dismiss"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Try again"</string>
     <string name="sort_name" msgid="9183560467917256779">"By name"</string>
     <string name="sort_date" msgid="586080032956151448">"By date modified"</string>
     <string name="sort_size" msgid="3350681319735474741">"By size"</string>
diff --git a/packages/DocumentsUI/res/values-es-rUS/strings.xml b/packages/DocumentsUI/res/values-es-rUS/strings.xml
index 5936d83..6e805b9 100644
--- a/packages/DocumentsUI/res/values-es-rUS/strings.xml
+++ b/packages/DocumentsUI/res/values-es-rUS/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Seleccionar"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Descartar"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Reintentar"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
     <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-es/strings.xml b/packages/DocumentsUI/res/values-es/strings.xml
index 2ed67dd..8fa1d2e 100644
--- a/packages/DocumentsUI/res/values-es/strings.xml
+++ b/packages/DocumentsUI/res/values-es/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Seleccionar"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Reintentar"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nombre"</string>
     <string name="sort_date" msgid="586080032956151448">"Por fecha de modificación"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-et-rEE/strings.xml b/packages/DocumentsUI/res/values-et-rEE/strings.xml
index e32936f..7008885 100644
--- a/packages/DocumentsUI/res/values-et-rEE/strings.xml
+++ b/packages/DocumentsUI/res/values-et-rEE/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Vali"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopeeri"</string>
     <string name="button_move" msgid="2202666023104202232">"Teisalda"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Loobu"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Nime järgi"</string>
     <string name="sort_date" msgid="586080032956151448">"Muutmiskuupäeva järgi"</string>
     <string name="sort_size" msgid="3350681319735474741">"Suuruse järgi"</string>
diff --git a/packages/DocumentsUI/res/values-eu-rES/strings.xml b/packages/DocumentsUI/res/values-eu-rES/strings.xml
index a1b6fc2..17d7c66 100644
--- a/packages/DocumentsUI/res/values-eu-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-eu-rES/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Hautatu"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiatu"</string>
     <string name="button_move" msgid="2202666023104202232">"Mugitu"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Baztertu"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Izenaren arabera"</string>
     <string name="sort_date" msgid="586080032956151448">"Aldatze-dataren arabera"</string>
     <string name="sort_size" msgid="3350681319735474741">"Tamainaren arabera"</string>
diff --git a/packages/DocumentsUI/res/values-fa/strings.xml b/packages/DocumentsUI/res/values-fa/strings.xml
index bbbfe52..c4f6d58 100644
--- a/packages/DocumentsUI/res/values-fa/strings.xml
+++ b/packages/DocumentsUI/res/values-fa/strings.xml
@@ -22,7 +22,7 @@
     <string name="title_save" msgid="2433679664882857999">"ذخیره در"</string>
     <string name="menu_create_dir" msgid="5947289605844398389">"ایجاد پوشه"</string>
     <string name="menu_grid" msgid="6878021334497835259">"نمای جدولی"</string>
-    <string name="menu_list" msgid="7279285939892417279">"نمای فهرست‌وار"</string>
+    <string name="menu_list" msgid="7279285939892417279">"نمای فهرستی"</string>
     <string name="menu_sort" msgid="7677740407158414452">"مرتب‌سازی براساس"</string>
     <string name="menu_search" msgid="3816712084502856974">"جستجو"</string>
     <string name="menu_settings" msgid="6008033148948428823">"تنظیمات"</string>
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"انتخاب"</string>
     <string name="button_copy" msgid="8706475544635021302">"کپی"</string>
     <string name="button_move" msgid="2202666023104202232">"انتقال"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"نپذیرفتن"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"براساس نام"</string>
     <string name="sort_date" msgid="586080032956151448">"براساس تاریخ اصلاح"</string>
     <string name="sort_size" msgid="3350681319735474741">"براساس اندازه"</string>
diff --git a/packages/DocumentsUI/res/values-fi/strings.xml b/packages/DocumentsUI/res/values-fi/strings.xml
index fd289a7..3e87300 100644
--- a/packages/DocumentsUI/res/values-fi/strings.xml
+++ b/packages/DocumentsUI/res/values-fi/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Valitse"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopioi"</string>
     <string name="button_move" msgid="2202666023104202232">"Siirrä"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Hylkää"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Nimen mukaan"</string>
     <string name="sort_date" msgid="586080032956151448">"Muokkauspäivän mukaan"</string>
     <string name="sort_size" msgid="3350681319735474741">"Koon mukaan"</string>
diff --git a/packages/DocumentsUI/res/values-fr-rCA/strings.xml b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
index 342fc97..3e82f34 100644
--- a/packages/DocumentsUI/res/values-fr-rCA/strings.xml
+++ b/packages/DocumentsUI/res/values-fr-rCA/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Sélectionner"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copier"</string>
     <string name="button_move" msgid="2202666023104202232">"Déplacer"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Faire disparaître"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
     <string name="sort_size" msgid="3350681319735474741">"Par taille"</string>
diff --git a/packages/DocumentsUI/res/values-fr/strings.xml b/packages/DocumentsUI/res/values-fr/strings.xml
index 7434e2f..0512ab1 100644
--- a/packages/DocumentsUI/res/values-fr/strings.xml
+++ b/packages/DocumentsUI/res/values-fr/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Sélectionner"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copier"</string>
     <string name="button_move" msgid="2202666023104202232">"Déplacer"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Fermer"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Réessayer"</string>
     <string name="sort_name" msgid="9183560467917256779">"Par nom"</string>
     <string name="sort_date" msgid="586080032956151448">"Par date de modification"</string>
     <string name="sort_size" msgid="3350681319735474741">"Par taille"</string>
diff --git a/packages/DocumentsUI/res/values-gl-rES/strings.xml b/packages/DocumentsUI/res/values-gl-rES/strings.xml
index b74018d..a1cd614 100644
--- a/packages/DocumentsUI/res/values-gl-rES/strings.xml
+++ b/packages/DocumentsUI/res/values-gl-rES/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Seleccionar"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificación"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamaño"</string>
diff --git a/packages/DocumentsUI/res/values-gu-rIN/strings.xml b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
index 58384c9..059fb2c 100644
--- a/packages/DocumentsUI/res/values-gu-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-gu-rIN/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"પસંદ કરો"</string>
     <string name="button_copy" msgid="8706475544635021302">"કૉપિ કરો"</string>
     <string name="button_move" msgid="2202666023104202232">"ખસેડો"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"છોડી દો"</string>
+    <string name="button_retry" msgid="4392027584153752797">"ફરીથી પ્રયત્ન કરો"</string>
     <string name="sort_name" msgid="9183560467917256779">"નામ દ્વારા"</string>
     <string name="sort_date" msgid="586080032956151448">"સંશોધન તારીખ દ્વારા"</string>
     <string name="sort_size" msgid="3350681319735474741">"કદ દ્વારા"</string>
diff --git a/packages/DocumentsUI/res/values-hi/strings.xml b/packages/DocumentsUI/res/values-hi/strings.xml
index b42c69c..8e33a00 100644
--- a/packages/DocumentsUI/res/values-hi/strings.xml
+++ b/packages/DocumentsUI/res/values-hi/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"चुनें"</string>
     <string name="button_copy" msgid="8706475544635021302">"कॉपी करें"</string>
     <string name="button_move" msgid="2202666023104202232">"ले जाएं"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ख़ारिज करें"</string>
+    <string name="button_retry" msgid="4392027584153752797">"पुनः प्रयास करें"</string>
     <string name="sort_name" msgid="9183560467917256779">"नाम के अनुसार"</string>
     <string name="sort_date" msgid="586080032956151448">"बदलाव के दिनांक के अनुसार"</string>
     <string name="sort_size" msgid="3350681319735474741">"आकार के अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-hr/strings.xml b/packages/DocumentsUI/res/values-hr/strings.xml
index 575c7ff..4774753 100644
--- a/packages/DocumentsUI/res/values-hr/strings.xml
+++ b/packages/DocumentsUI/res/values-hr/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Odaberi"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
     <string name="button_move" msgid="2202666023104202232">"Premjesti"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Odbaci"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Po nazivu"</string>
     <string name="sort_date" msgid="586080032956151448">"Po datumu izmjene"</string>
     <string name="sort_size" msgid="3350681319735474741">"Po veličini"</string>
diff --git a/packages/DocumentsUI/res/values-hu/strings.xml b/packages/DocumentsUI/res/values-hu/strings.xml
index 2d2e3c8..7a521ec 100644
--- a/packages/DocumentsUI/res/values-hu/strings.xml
+++ b/packages/DocumentsUI/res/values-hu/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Kiválasztás"</string>
     <string name="button_copy" msgid="8706475544635021302">"Másolás"</string>
     <string name="button_move" msgid="2202666023104202232">"Áthelyezés"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Elvetés"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Név szerint"</string>
     <string name="sort_date" msgid="586080032956151448">"Módosítás dátuma szerint"</string>
     <string name="sort_size" msgid="3350681319735474741">"Méret szerint"</string>
diff --git a/packages/DocumentsUI/res/values-hy-rAM/strings.xml b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
index 0a4e7a3..95d73f0 100644
--- a/packages/DocumentsUI/res/values-hy-rAM/strings.xml
+++ b/packages/DocumentsUI/res/values-hy-rAM/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Ընտրել"</string>
     <string name="button_copy" msgid="8706475544635021302">"Պատճենել"</string>
     <string name="button_move" msgid="2202666023104202232">"Տեղափոխել"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Փակել"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Ըստ անվան"</string>
     <string name="sort_date" msgid="586080032956151448">"Ըստ փոփոխման ամսաթվի"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ըստ չափի"</string>
diff --git a/packages/DocumentsUI/res/values-in/strings.xml b/packages/DocumentsUI/res/values-in/strings.xml
index 59aadf1..63d415c 100644
--- a/packages/DocumentsUI/res/values-in/strings.xml
+++ b/packages/DocumentsUI/res/values-in/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Pilih"</string>
     <string name="button_copy" msgid="8706475544635021302">"Salin"</string>
     <string name="button_move" msgid="2202666023104202232">"Pindahkan"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Tutup"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Coba Lagi"</string>
     <string name="sort_name" msgid="9183560467917256779">"Menurut nama"</string>
     <string name="sort_date" msgid="586080032956151448">"Menurut tanggal diubah"</string>
     <string name="sort_size" msgid="3350681319735474741">"Menurut ukuran"</string>
diff --git a/packages/DocumentsUI/res/values-is-rIS/strings.xml b/packages/DocumentsUI/res/values-is-rIS/strings.xml
index a0f4987..0c0e47f 100644
--- a/packages/DocumentsUI/res/values-is-rIS/strings.xml
+++ b/packages/DocumentsUI/res/values-is-rIS/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Velja"</string>
     <string name="button_copy" msgid="8706475544635021302">"Afrita"</string>
     <string name="button_move" msgid="2202666023104202232">"Færa"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Hunsa"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Reyna aftur"</string>
     <string name="sort_name" msgid="9183560467917256779">"Eftir heiti"</string>
     <string name="sort_date" msgid="586080032956151448">"Eftir breytingadags."</string>
     <string name="sort_size" msgid="3350681319735474741">"Eftir stærð"</string>
diff --git a/packages/DocumentsUI/res/values-it/strings.xml b/packages/DocumentsUI/res/values-it/strings.xml
index ce837da..de129a7 100644
--- a/packages/DocumentsUI/res/values-it/strings.xml
+++ b/packages/DocumentsUI/res/values-it/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Seleziona"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copia"</string>
     <string name="button_move" msgid="2202666023104202232">"Sposta"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ignora"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Riprova"</string>
     <string name="sort_name" msgid="9183560467917256779">"Per nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Per data di modifica"</string>
     <string name="sort_size" msgid="3350681319735474741">"Per dimensioni"</string>
diff --git a/packages/DocumentsUI/res/values-iw/strings.xml b/packages/DocumentsUI/res/values-iw/strings.xml
index 89e6403..dbe4630 100644
--- a/packages/DocumentsUI/res/values-iw/strings.xml
+++ b/packages/DocumentsUI/res/values-iw/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"בחר"</string>
     <string name="button_copy" msgid="8706475544635021302">"העתק"</string>
     <string name="button_move" msgid="2202666023104202232">"העבר"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"הסר"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"לפי שם"</string>
     <string name="sort_date" msgid="586080032956151448">"לפי תאריך שינוי"</string>
     <string name="sort_size" msgid="3350681319735474741">"לפי גודל"</string>
diff --git a/packages/DocumentsUI/res/values-ja/strings.xml b/packages/DocumentsUI/res/values-ja/strings.xml
index 92e1023..45f0ea1 100644
--- a/packages/DocumentsUI/res/values-ja/strings.xml
+++ b/packages/DocumentsUI/res/values-ja/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"選択"</string>
     <string name="button_copy" msgid="8706475544635021302">"コピー"</string>
     <string name="button_move" msgid="2202666023104202232">"移動"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"表示しない"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"名前順"</string>
     <string name="sort_date" msgid="586080032956151448">"更新日順"</string>
     <string name="sort_size" msgid="3350681319735474741">"サイズ順"</string>
diff --git a/packages/DocumentsUI/res/values-ka-rGE/strings.xml b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
index 9a324ba..114e73c 100644
--- a/packages/DocumentsUI/res/values-ka-rGE/strings.xml
+++ b/packages/DocumentsUI/res/values-ka-rGE/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"არჩევა"</string>
     <string name="button_copy" msgid="8706475544635021302">"კოპირება"</string>
     <string name="button_move" msgid="2202666023104202232">"გადაადგილება"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"დახურვა"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"სახელით"</string>
     <string name="sort_date" msgid="586080032956151448">"ცვლილების თარიღით"</string>
     <string name="sort_size" msgid="3350681319735474741">"ზომით"</string>
diff --git a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
index 66f69f5..af123c6 100644
--- a/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
+++ b/packages/DocumentsUI/res/values-kk-rKZ/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Таңдау"</string>
     <string name="button_copy" msgid="8706475544635021302">"Көшіру"</string>
     <string name="button_move" msgid="2202666023104202232">"Жылжыту"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Өшіру"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Атауы бойынша"</string>
     <string name="sort_date" msgid="586080032956151448">"Өзгертілген мерзімі бойынша"</string>
     <string name="sort_size" msgid="3350681319735474741">"Өлшемі бойынша"</string>
diff --git a/packages/DocumentsUI/res/values-km-rKH/strings.xml b/packages/DocumentsUI/res/values-km-rKH/strings.xml
index 5249d97..8f3feae 100644
--- a/packages/DocumentsUI/res/values-km-rKH/strings.xml
+++ b/packages/DocumentsUI/res/values-km-rKH/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"ជ្រើស"</string>
     <string name="button_copy" msgid="8706475544635021302">"ចម្លង"</string>
     <string name="button_move" msgid="2202666023104202232">"ផ្លាស់ទី"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"បដិសេធ"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"តាម​ឈ្មោះ"</string>
     <string name="sort_date" msgid="586080032956151448">"តាម​កាលបរិច្ឆេទ​បាន​កែប្រែ"</string>
     <string name="sort_size" msgid="3350681319735474741">"តាម​​ទំហំ"</string>
diff --git a/packages/DocumentsUI/res/values-kn-rIN/strings.xml b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
index d5eda84..826cf1e 100644
--- a/packages/DocumentsUI/res/values-kn-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-kn-rIN/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"ಆಯ್ಕೆಮಾಡು"</string>
     <string name="button_copy" msgid="8706475544635021302">"ನಕಲಿಸು"</string>
     <string name="button_move" msgid="2202666023104202232">"ಸರಿಸು"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ವಜಾಗೊಳಿಸಿ"</string>
+    <string name="button_retry" msgid="4392027584153752797">"ಮತ್ತೆ ಪ್ರಯತ್ನಿಸಿ"</string>
     <string name="sort_name" msgid="9183560467917256779">"ಹೆಸರಿನ ಪ್ರಕಾರ"</string>
     <string name="sort_date" msgid="586080032956151448">"ಮಾರ್ಪಡಿಸಿರುವ ದಿನಾಂಕದ ಪ್ರಕಾರ"</string>
     <string name="sort_size" msgid="3350681319735474741">"ಗಾತ್ರದ ಪ್ರಕಾರ"</string>
diff --git a/packages/DocumentsUI/res/values-ko/strings.xml b/packages/DocumentsUI/res/values-ko/strings.xml
index 77a0df6..322b43b 100644
--- a/packages/DocumentsUI/res/values-ko/strings.xml
+++ b/packages/DocumentsUI/res/values-ko/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"선택"</string>
     <string name="button_copy" msgid="8706475544635021302">"복사"</string>
     <string name="button_move" msgid="2202666023104202232">"이동"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"닫기"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"이름순"</string>
     <string name="sort_date" msgid="586080032956151448">"수정된 날짜순"</string>
     <string name="sort_size" msgid="3350681319735474741">"크기순"</string>
diff --git a/packages/DocumentsUI/res/values-ky-rKG/strings.xml b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
index 14a6331..c8aa69e 100644
--- a/packages/DocumentsUI/res/values-ky-rKG/strings.xml
+++ b/packages/DocumentsUI/res/values-ky-rKG/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Тандоо"</string>
     <string name="button_copy" msgid="8706475544635021302">"Көчүрүү"</string>
     <string name="button_move" msgid="2202666023104202232">"Жылдыруу"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Этибарга албоо"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Аты боюнча"</string>
     <string name="sort_date" msgid="586080032956151448">"Өзгөртүлгөн күнү боюнча"</string>
     <string name="sort_size" msgid="3350681319735474741">"Өлчөмү боюнча"</string>
diff --git a/packages/DocumentsUI/res/values-lo-rLA/strings.xml b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
index 2d099f4..dedfa05 100644
--- a/packages/DocumentsUI/res/values-lo-rLA/strings.xml
+++ b/packages/DocumentsUI/res/values-lo-rLA/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"ເລືອກ"</string>
     <string name="button_copy" msgid="8706475544635021302">"ສຳເນົາ"</string>
     <string name="button_move" msgid="2202666023104202232">"ຍ້າຍ"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ປິດໄວ້"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"ຕາມຊື່"</string>
     <string name="sort_date" msgid="586080032956151448">"ຕາມວັນທີທີ່ແກ້ໄຂ"</string>
     <string name="sort_size" msgid="3350681319735474741">"ຕາມຂະໜາດ"</string>
diff --git a/packages/DocumentsUI/res/values-lt/strings.xml b/packages/DocumentsUI/res/values-lt/strings.xml
index 7b458add..0c8b443 100644
--- a/packages/DocumentsUI/res/values-lt/strings.xml
+++ b/packages/DocumentsUI/res/values-lt/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Pasirinkti"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopijuoti"</string>
     <string name="button_move" msgid="2202666023104202232">"Perkelti"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Atsisakyti"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Pagal pavadinimą"</string>
     <string name="sort_date" msgid="586080032956151448">"Pagal keitimo datą"</string>
     <string name="sort_size" msgid="3350681319735474741">"Pagal dydį"</string>
diff --git a/packages/DocumentsUI/res/values-lv/strings.xml b/packages/DocumentsUI/res/values-lv/strings.xml
index 44909ce..5c79554 100644
--- a/packages/DocumentsUI/res/values-lv/strings.xml
+++ b/packages/DocumentsUI/res/values-lv/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Atlasīt"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopēt"</string>
     <string name="button_move" msgid="2202666023104202232">"Pārvietot"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Noraidīt"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Pēc nosaukuma"</string>
     <string name="sort_date" msgid="586080032956151448">"Pēc pārveidošanas datuma"</string>
     <string name="sort_size" msgid="3350681319735474741">"Pēc lieluma"</string>
diff --git a/packages/DocumentsUI/res/values-mk-rMK/strings.xml b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
index 7408d0b..b2cb9f1 100644
--- a/packages/DocumentsUI/res/values-mk-rMK/strings.xml
+++ b/packages/DocumentsUI/res/values-mk-rMK/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Избери"</string>
     <string name="button_copy" msgid="8706475544635021302">"Копирај"</string>
     <string name="button_move" msgid="2202666023104202232">"Премести"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Отфрли"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"По име"</string>
     <string name="sort_date" msgid="586080032956151448">"Изменети по датум"</string>
     <string name="sort_size" msgid="3350681319735474741">"По големина"</string>
diff --git a/packages/DocumentsUI/res/values-ml-rIN/strings.xml b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
index af21db9..07efa66 100644
--- a/packages/DocumentsUI/res/values-ml-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ml-rIN/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"തിരഞ്ഞെടുക്കുക"</string>
     <string name="button_copy" msgid="8706475544635021302">"പകര്‍ത്തുക"</string>
     <string name="button_move" msgid="2202666023104202232">"നീക്കുക"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ഡിസ്മിസ് ചെയ്യുക"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"പേര് പ്രകാരം"</string>
     <string name="sort_date" msgid="586080032956151448">"പരിഷ്‌ക്കരിച്ച തീയതി പ്രകാരം"</string>
     <string name="sort_size" msgid="3350681319735474741">"വലുപ്പം പ്രകാരം"</string>
diff --git a/packages/DocumentsUI/res/values-mn-rMN/strings.xml b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
index 1475e08..d45778c 100644
--- a/packages/DocumentsUI/res/values-mn-rMN/strings.xml
+++ b/packages/DocumentsUI/res/values-mn-rMN/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Сонгох"</string>
     <string name="button_copy" msgid="8706475544635021302">"Хуулах"</string>
     <string name="button_move" msgid="2202666023104202232">"Зөөх"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Алгасах"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Нэрээр"</string>
     <string name="sort_date" msgid="586080032956151448">"Өөрчлөгдсөн огноогоор"</string>
     <string name="sort_size" msgid="3350681319735474741">"Хэмжээгээр"</string>
diff --git a/packages/DocumentsUI/res/values-mr-rIN/strings.xml b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
index b7654881..8d70143 100644
--- a/packages/DocumentsUI/res/values-mr-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-mr-rIN/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"निवडा"</string>
     <string name="button_copy" msgid="8706475544635021302">"कॉपी करा"</string>
     <string name="button_move" msgid="2202666023104202232">"हलवा"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"डिसमिस करा"</string>
+    <string name="button_retry" msgid="4392027584153752797">"पुन्‍हा प्रयत्न करा"</string>
     <string name="sort_name" msgid="9183560467917256779">"नावानुसार"</string>
     <string name="sort_date" msgid="586080032956151448">"सुधारित केलेल्‍या तारखेनुसार"</string>
     <string name="sort_size" msgid="3350681319735474741">"आकारानुसार"</string>
diff --git a/packages/DocumentsUI/res/values-ms-rMY/strings.xml b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
index 4682957..2250109 100644
--- a/packages/DocumentsUI/res/values-ms-rMY/strings.xml
+++ b/packages/DocumentsUI/res/values-ms-rMY/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Pilih"</string>
     <string name="button_copy" msgid="8706475544635021302">"Salin"</string>
     <string name="button_move" msgid="2202666023104202232">"Alihkan"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Tolak"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Mengikut nama"</string>
     <string name="sort_date" msgid="586080032956151448">"Mengikut tarikh diubah"</string>
     <string name="sort_size" msgid="3350681319735474741">"Mengikut saiz"</string>
diff --git a/packages/DocumentsUI/res/values-my-rMM/strings.xml b/packages/DocumentsUI/res/values-my-rMM/strings.xml
index a422898..480c27b 100644
--- a/packages/DocumentsUI/res/values-my-rMM/strings.xml
+++ b/packages/DocumentsUI/res/values-my-rMM/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"ရွေးရန်"</string>
     <string name="button_copy" msgid="8706475544635021302">"ကူးယူရန်"</string>
     <string name="button_move" msgid="2202666023104202232">"ရွေ့မည်"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ပယ်ရန်"</string>
+    <string name="button_retry" msgid="4392027584153752797">"ထပ် စမ်းကြည့်ပါ"</string>
     <string name="sort_name" msgid="9183560467917256779">"အမည်ဖြင့်"</string>
     <string name="sort_date" msgid="586080032956151448">"ပြင်ဆင်မှု ရက်စွဲဖြင့်"</string>
     <string name="sort_size" msgid="3350681319735474741">"အရွယ်အစားဖြင့်"</string>
diff --git a/packages/DocumentsUI/res/values-nb/strings.xml b/packages/DocumentsUI/res/values-nb/strings.xml
index 5bcc50f..48355aa 100644
--- a/packages/DocumentsUI/res/values-nb/strings.xml
+++ b/packages/DocumentsUI/res/values-nb/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Velg"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiér"</string>
     <string name="button_move" msgid="2202666023104202232">"Flytt"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Avvis"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Prøv på nytt"</string>
     <string name="sort_name" msgid="9183560467917256779">"Etter navn"</string>
     <string name="sort_date" msgid="586080032956151448">"Etter endringsdato"</string>
     <string name="sort_size" msgid="3350681319735474741">"Etter størrelse"</string>
diff --git a/packages/DocumentsUI/res/values-ne-rNP/strings.xml b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
index b121035..53942c1 100644
--- a/packages/DocumentsUI/res/values-ne-rNP/strings.xml
+++ b/packages/DocumentsUI/res/values-ne-rNP/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"चयन गर्नुहोस्"</string>
     <string name="button_copy" msgid="8706475544635021302">"प्रतिलिपि बनाउनुहोस्"</string>
     <string name="button_move" msgid="2202666023104202232">"सार्नुहोस्"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"खारेज गर्नुहोस्"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"नाम अनुसार"</string>
     <string name="sort_date" msgid="586080032956151448">"परिमार्जित मिति अनुसार"</string>
     <string name="sort_size" msgid="3350681319735474741">"आकार अनुसार"</string>
diff --git a/packages/DocumentsUI/res/values-nl/strings.xml b/packages/DocumentsUI/res/values-nl/strings.xml
index 88ef0bf..d3e6bbe 100644
--- a/packages/DocumentsUI/res/values-nl/strings.xml
+++ b/packages/DocumentsUI/res/values-nl/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Selecteren"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiëren"</string>
     <string name="button_move" msgid="2202666023104202232">"Verplaatsen"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Sluiten"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Opnieuw proberen"</string>
     <string name="sort_name" msgid="9183560467917256779">"Op naam"</string>
     <string name="sort_date" msgid="586080032956151448">"Op aanpassingsdatum"</string>
     <string name="sort_size" msgid="3350681319735474741">"Op grootte"</string>
diff --git a/packages/DocumentsUI/res/values-pa-rIN/strings.xml b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
index a55fc27..3b14396 100644
--- a/packages/DocumentsUI/res/values-pa-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-pa-rIN/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"ਚੁਣੋ"</string>
     <string name="button_copy" msgid="8706475544635021302">"ਕਾਪੀ ਕਰੋ"</string>
     <string name="button_move" msgid="2202666023104202232">"ਮੂਵ ਕਰੋ"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ਬਰਖਾਸਤ ਕਰੋ"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"ਨਾਮ ਮੁਤਾਬਕ"</string>
     <string name="sort_date" msgid="586080032956151448">"ਤਾਰੀਖ ਮੁਤਾਬਕ ਸੰਸ਼ੋਧਿਤ"</string>
     <string name="sort_size" msgid="3350681319735474741">"ਆਕਾਰ ਮੁਤਾਬਕ"</string>
diff --git a/packages/DocumentsUI/res/values-pl/strings.xml b/packages/DocumentsUI/res/values-pl/strings.xml
index 0099e5a..3e4ef68 100644
--- a/packages/DocumentsUI/res/values-pl/strings.xml
+++ b/packages/DocumentsUI/res/values-pl/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Wybierz"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiuj"</string>
     <string name="button_move" msgid="2202666023104202232">"Przenieś"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Zamknij"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Według nazwy"</string>
     <string name="sort_date" msgid="586080032956151448">"Według daty edycji"</string>
     <string name="sort_size" msgid="3350681319735474741">"Według rozmiaru"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rBR/strings.xml b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
index 18506dc..ca984cf 100644
--- a/packages/DocumentsUI/res/values-pt-rBR/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rBR/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Selecionar"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Dispensar"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string>
diff --git a/packages/DocumentsUI/res/values-pt-rPT/strings.xml b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
index adf6ec9..ab67358 100644
--- a/packages/DocumentsUI/res/values-pt-rPT/strings.xml
+++ b/packages/DocumentsUI/res/values-pt-rPT/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Selecionar"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ignorar"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string>
diff --git a/packages/DocumentsUI/res/values-pt/strings.xml b/packages/DocumentsUI/res/values-pt/strings.xml
index 18506dc..ca984cf 100644
--- a/packages/DocumentsUI/res/values-pt/strings.xml
+++ b/packages/DocumentsUI/res/values-pt/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Selecionar"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiar"</string>
     <string name="button_move" msgid="2202666023104202232">"Mover"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Dispensar"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Tentar novamente"</string>
     <string name="sort_name" msgid="9183560467917256779">"Por nome"</string>
     <string name="sort_date" msgid="586080032956151448">"Por data de modificação"</string>
     <string name="sort_size" msgid="3350681319735474741">"Por tamanho"</string>
diff --git a/packages/DocumentsUI/res/values-ro/strings.xml b/packages/DocumentsUI/res/values-ro/strings.xml
index 1b046a3..e927b78 100644
--- a/packages/DocumentsUI/res/values-ro/strings.xml
+++ b/packages/DocumentsUI/res/values-ro/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Selectați"</string>
     <string name="button_copy" msgid="8706475544635021302">"Copiați"</string>
     <string name="button_move" msgid="2202666023104202232">"Mutați"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Închideți"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Încercați din nou"</string>
     <string name="sort_name" msgid="9183560467917256779">"După nume"</string>
     <string name="sort_date" msgid="586080032956151448">"După data modificării"</string>
     <string name="sort_size" msgid="3350681319735474741">"După dimensiune"</string>
diff --git a/packages/DocumentsUI/res/values-ru/strings.xml b/packages/DocumentsUI/res/values-ru/strings.xml
index 84ae160..cdf20ca 100644
--- a/packages/DocumentsUI/res/values-ru/strings.xml
+++ b/packages/DocumentsUI/res/values-ru/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Выбрать"</string>
     <string name="button_copy" msgid="8706475544635021302">"Копировать"</string>
     <string name="button_move" msgid="2202666023104202232">"Переместить"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Скрыть"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"По названию"</string>
     <string name="sort_date" msgid="586080032956151448">"По дате изменения"</string>
     <string name="sort_size" msgid="3350681319735474741">"По размеру"</string>
diff --git a/packages/DocumentsUI/res/values-si-rLK/strings.xml b/packages/DocumentsUI/res/values-si-rLK/strings.xml
index d9d5818..138f8a6 100644
--- a/packages/DocumentsUI/res/values-si-rLK/strings.xml
+++ b/packages/DocumentsUI/res/values-si-rLK/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"තෝරන්න"</string>
     <string name="button_copy" msgid="8706475544635021302">"පිටපත් කිරීම"</string>
     <string name="button_move" msgid="2202666023104202232">"ගෙන යන්න"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ඉවතලන්න"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"නමින්"</string>
     <string name="sort_date" msgid="586080032956151448">"වෙනස් කරන ලද දිනයෙන්"</string>
     <string name="sort_size" msgid="3350681319735474741">"ප්‍රමාණය මගින්"</string>
diff --git a/packages/DocumentsUI/res/values-sk/strings.xml b/packages/DocumentsUI/res/values-sk/strings.xml
index e0ff5fc..4310819 100644
--- a/packages/DocumentsUI/res/values-sk/strings.xml
+++ b/packages/DocumentsUI/res/values-sk/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Vybrať"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopírovať"</string>
     <string name="button_move" msgid="2202666023104202232">"Presunúť"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Odmietnuť"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Podľa názvu"</string>
     <string name="sort_date" msgid="586080032956151448">"Podľa dátumu zmeny"</string>
     <string name="sort_size" msgid="3350681319735474741">"Podľa veľkosti"</string>
diff --git a/packages/DocumentsUI/res/values-sl/strings.xml b/packages/DocumentsUI/res/values-sl/strings.xml
index 83e5124..c9982a7 100644
--- a/packages/DocumentsUI/res/values-sl/strings.xml
+++ b/packages/DocumentsUI/res/values-sl/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Izberi"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiraj"</string>
     <string name="button_move" msgid="2202666023104202232">"Premik"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Opusti"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Po imenu"</string>
     <string name="sort_date" msgid="586080032956151448">"Po datumu spremembe"</string>
     <string name="sort_size" msgid="3350681319735474741">"Po velikosti"</string>
diff --git a/packages/DocumentsUI/res/values-sq-rAL/strings.xml b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
index 981daf2..f1ee1bc 100644
--- a/packages/DocumentsUI/res/values-sq-rAL/strings.xml
+++ b/packages/DocumentsUI/res/values-sq-rAL/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Zgjidh"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopjo"</string>
     <string name="button_move" msgid="2202666023104202232">"Zhvendos"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Largoje"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Sipas emrit"</string>
     <string name="sort_date" msgid="586080032956151448">"Sipas datës së modifikimit"</string>
     <string name="sort_size" msgid="3350681319735474741">"Sipas madhësisë"</string>
diff --git a/packages/DocumentsUI/res/values-sr/strings.xml b/packages/DocumentsUI/res/values-sr/strings.xml
index bd0e9af..c5116c2 100644
--- a/packages/DocumentsUI/res/values-sr/strings.xml
+++ b/packages/DocumentsUI/res/values-sr/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Изабери"</string>
     <string name="button_copy" msgid="8706475544635021302">"Копирај"</string>
     <string name="button_move" msgid="2202666023104202232">"Премести"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Одбаци"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Према имену"</string>
     <string name="sort_date" msgid="586080032956151448">"Према датуму измене"</string>
     <string name="sort_size" msgid="3350681319735474741">"Према величини"</string>
diff --git a/packages/DocumentsUI/res/values-sv/strings.xml b/packages/DocumentsUI/res/values-sv/strings.xml
index 2569e00..06e6514 100644
--- a/packages/DocumentsUI/res/values-sv/strings.xml
+++ b/packages/DocumentsUI/res/values-sv/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Välj"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopiera"</string>
     <string name="button_move" msgid="2202666023104202232">"Flytta"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ta bort permanent"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Försök igen"</string>
     <string name="sort_name" msgid="9183560467917256779">"Efter namn"</string>
     <string name="sort_date" msgid="586080032956151448">"Efter ändringsdatum"</string>
     <string name="sort_size" msgid="3350681319735474741">"Efter storlek"</string>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index ce186d7..79bae1f 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Teua"</string>
     <string name="button_copy" msgid="8706475544635021302">"Nakili"</string>
     <string name="button_move" msgid="2202666023104202232">"Hamisha"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Ondoa"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Jaribu Tena"</string>
     <string name="sort_name" msgid="9183560467917256779">"Kwa jina"</string>
     <string name="sort_date" msgid="586080032956151448">"Kwa tarehe viliporekebishwa"</string>
     <string name="sort_size" msgid="3350681319735474741">"Kwa ukubwa"</string>
diff --git a/packages/DocumentsUI/res/values-ta-rIN/strings.xml b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
index b7b9c09..117aabc 100644
--- a/packages/DocumentsUI/res/values-ta-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-ta-rIN/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"தேர்ந்தெடு"</string>
     <string name="button_copy" msgid="8706475544635021302">"நகலெடு"</string>
     <string name="button_move" msgid="2202666023104202232">"நகர்த்து"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"நிராகரி"</string>
+    <string name="button_retry" msgid="4392027584153752797">"மீண்டும் முயற்சிக்கவும்"</string>
     <string name="sort_name" msgid="9183560467917256779">"பெயரின்படி"</string>
     <string name="sort_date" msgid="586080032956151448">"திருத்தப்பட்ட தேதியின்படி"</string>
     <string name="sort_size" msgid="3350681319735474741">"அளவின்படி"</string>
diff --git a/packages/DocumentsUI/res/values-te-rIN/strings.xml b/packages/DocumentsUI/res/values-te-rIN/strings.xml
index 7a81486..21b7f58 100644
--- a/packages/DocumentsUI/res/values-te-rIN/strings.xml
+++ b/packages/DocumentsUI/res/values-te-rIN/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"ఎంచుకోండి"</string>
     <string name="button_copy" msgid="8706475544635021302">"కాపీ చేయి"</string>
     <string name="button_move" msgid="2202666023104202232">"తరలించు"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"తీసివేయి"</string>
+    <string name="button_retry" msgid="4392027584153752797">"మళ్లీ ప్రయత్నించు"</string>
     <string name="sort_name" msgid="9183560467917256779">"పేరు ద్వారా"</string>
     <string name="sort_date" msgid="586080032956151448">"సవరించిన తేదీ ద్వారా"</string>
     <string name="sort_size" msgid="3350681319735474741">"పరిమాణం ద్వారా"</string>
diff --git a/packages/DocumentsUI/res/values-th/strings.xml b/packages/DocumentsUI/res/values-th/strings.xml
index 87c0a73..8a49708 100644
--- a/packages/DocumentsUI/res/values-th/strings.xml
+++ b/packages/DocumentsUI/res/values-th/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"เลือก"</string>
     <string name="button_copy" msgid="8706475544635021302">"คัดลอก"</string>
     <string name="button_move" msgid="2202666023104202232">"ย้าย"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"ปิด"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"ตามชื่อ"</string>
     <string name="sort_date" msgid="586080032956151448">"ตามวันที่ที่ปรับเปลี่ยน"</string>
     <string name="sort_size" msgid="3350681319735474741">"ตามขนาด"</string>
diff --git a/packages/DocumentsUI/res/values-tl/strings.xml b/packages/DocumentsUI/res/values-tl/strings.xml
index eaef936..5c0dc12 100644
--- a/packages/DocumentsUI/res/values-tl/strings.xml
+++ b/packages/DocumentsUI/res/values-tl/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Pumili"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopyahin"</string>
     <string name="button_move" msgid="2202666023104202232">"Ilipat"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"I-dismiss"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Ayon sa pangalan"</string>
     <string name="sort_date" msgid="586080032956151448">"Ayon sa petsa ng pagbago"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ayon sa laki"</string>
diff --git a/packages/DocumentsUI/res/values-tr/strings.xml b/packages/DocumentsUI/res/values-tr/strings.xml
index 8c0596f..092b38e 100644
--- a/packages/DocumentsUI/res/values-tr/strings.xml
+++ b/packages/DocumentsUI/res/values-tr/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Seç"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopyala"</string>
     <string name="button_move" msgid="2202666023104202232">"Taşı"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Kapat"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Ada göre"</string>
     <string name="sort_date" msgid="586080032956151448">"Değişiklik tarihine göre"</string>
     <string name="sort_size" msgid="3350681319735474741">"Boyuta göre"</string>
diff --git a/packages/DocumentsUI/res/values-uk/strings.xml b/packages/DocumentsUI/res/values-uk/strings.xml
index 9bbc59a..dff37c3 100644
--- a/packages/DocumentsUI/res/values-uk/strings.xml
+++ b/packages/DocumentsUI/res/values-uk/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Вибрати"</string>
     <string name="button_copy" msgid="8706475544635021302">"Копіювати"</string>
     <string name="button_move" msgid="2202666023104202232">"Перемістити"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Закрити"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Повторити спробу"</string>
     <string name="sort_name" msgid="9183560467917256779">"За назвою"</string>
     <string name="sort_date" msgid="586080032956151448">"За датою змінення"</string>
     <string name="sort_size" msgid="3350681319735474741">"За розміром"</string>
diff --git a/packages/DocumentsUI/res/values-ur-rPK/strings.xml b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
index 0c12aa1..82822ec 100644
--- a/packages/DocumentsUI/res/values-ur-rPK/strings.xml
+++ b/packages/DocumentsUI/res/values-ur-rPK/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"منتخب کریں"</string>
     <string name="button_copy" msgid="8706475544635021302">"کاپی کریں"</string>
     <string name="button_move" msgid="2202666023104202232">"منتقل کریں"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"برخاست کریں"</string>
+    <string name="button_retry" msgid="4392027584153752797">"دوبارہ کوشش کریں"</string>
     <string name="sort_name" msgid="9183560467917256779">"نام کے لحاظ سے"</string>
     <string name="sort_date" msgid="586080032956151448">"ترمیم کی تاریخ کے لحاظ سے"</string>
     <string name="sort_size" msgid="3350681319735474741">"سائز کے لحاظ سے"</string>
diff --git a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
index ec91885..d0cfacc 100644
--- a/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
+++ b/packages/DocumentsUI/res/values-uz-rUZ/strings.xml
@@ -24,7 +24,7 @@
     <string name="menu_grid" msgid="6878021334497835259">"Katak ko‘rinishida"</string>
     <string name="menu_list" msgid="7279285939892417279">"Ro‘yxat ko‘rinishida"</string>
     <string name="menu_sort" msgid="7677740407158414452">"Saralash"</string>
-    <string name="menu_search" msgid="3816712084502856974">"Izlash"</string>
+    <string name="menu_search" msgid="3816712084502856974">"Qidirish"</string>
     <string name="menu_settings" msgid="6008033148948428823">"Sozlamalar"</string>
     <string name="menu_open" msgid="432922957274920903">"Ochish"</string>
     <string name="menu_save" msgid="2394743337684426338">"Saqlash"</string>
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Tanlash"</string>
     <string name="button_copy" msgid="8706475544635021302">"Nusxalash"</string>
     <string name="button_move" msgid="2202666023104202232">"Ko‘chirib o‘tkazish"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"O‘chirish"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Nomi bo‘yicha"</string>
     <string name="sort_date" msgid="586080032956151448">"Tahrir sanasi bo‘yicha"</string>
     <string name="sort_size" msgid="3350681319735474741">"Hajmi bo‘yicha"</string>
diff --git a/packages/DocumentsUI/res/values-vi/strings.xml b/packages/DocumentsUI/res/values-vi/strings.xml
index a652ecc..4583362 100644
--- a/packages/DocumentsUI/res/values-vi/strings.xml
+++ b/packages/DocumentsUI/res/values-vi/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"Chọn"</string>
     <string name="button_copy" msgid="8706475544635021302">"Sao chép"</string>
     <string name="button_move" msgid="2202666023104202232">"Di chuyển"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Loại bỏ"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"Theo tên"</string>
     <string name="sort_date" msgid="586080032956151448">"Theo ngày sửa đổi"</string>
     <string name="sort_size" msgid="3350681319735474741">"Theo kích thước"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rCN/strings.xml b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
index b0f5480..d577e14 100644
--- a/packages/DocumentsUI/res/values-zh-rCN/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rCN/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"选择"</string>
     <string name="button_copy" msgid="8706475544635021302">"复制"</string>
     <string name="button_move" msgid="2202666023104202232">"移动"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"关闭"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"按名称"</string>
     <string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
     <string name="sort_size" msgid="3350681319735474741">"按大小"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rHK/strings.xml b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
index 220b716..3d44047 100644
--- a/packages/DocumentsUI/res/values-zh-rHK/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rHK/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"選取"</string>
     <string name="button_copy" msgid="8706475544635021302">"複製"</string>
     <string name="button_move" msgid="2202666023104202232">"移動"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"按名稱"</string>
     <string name="sort_date" msgid="586080032956151448">"按修改日期"</string>
     <string name="sort_size" msgid="3350681319735474741">"按大小"</string>
diff --git a/packages/DocumentsUI/res/values-zh-rTW/strings.xml b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
index 9c21aa5..aaad98c8 100644
--- a/packages/DocumentsUI/res/values-zh-rTW/strings.xml
+++ b/packages/DocumentsUI/res/values-zh-rTW/strings.xml
@@ -44,6 +44,9 @@
     <string name="button_select" msgid="527196987259139214">"選取"</string>
     <string name="button_copy" msgid="8706475544635021302">"複製"</string>
     <string name="button_move" msgid="2202666023104202232">"移動"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"關閉"</string>
+    <!-- no translation found for button_retry (4392027584153752797) -->
+    <skip />
     <string name="sort_name" msgid="9183560467917256779">"依名稱"</string>
     <string name="sort_date" msgid="586080032956151448">"依修改日期"</string>
     <string name="sort_size" msgid="3350681319735474741">"依大小"</string>
diff --git a/packages/DocumentsUI/res/values-zu/strings.xml b/packages/DocumentsUI/res/values-zu/strings.xml
index 5ce9f12..8f20cc4 100644
--- a/packages/DocumentsUI/res/values-zu/strings.xml
+++ b/packages/DocumentsUI/res/values-zu/strings.xml
@@ -44,6 +44,8 @@
     <string name="button_select" msgid="527196987259139214">"Khetha"</string>
     <string name="button_copy" msgid="8706475544635021302">"Kopisha"</string>
     <string name="button_move" msgid="2202666023104202232">"Hambisa"</string>
+    <string name="button_dismiss" msgid="3714065566893946085">"Cashisa"</string>
+    <string name="button_retry" msgid="4392027584153752797">"Zama futhi"</string>
     <string name="sort_name" msgid="9183560467917256779">"Ngegama"</string>
     <string name="sort_date" msgid="586080032956151448">"Ngedethi yokuguqula"</string>
     <string name="sort_size" msgid="3350681319735474741">"Ngosayizi"</string>
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ed7820b..ce5b174 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -15,5 +15,5 @@
 -->
 
 <resources>
-    <bool name="productivity_device">true</bool>
+    <bool name="productivity_device">false</bool>
 </resources>
diff --git a/packages/DocumentsUI/res/values/strings.xml b/packages/DocumentsUI/res/values/strings.xml
index 28018f8e..a4acb604 100644
--- a/packages/DocumentsUI/res/values/strings.xml
+++ b/packages/DocumentsUI/res/values/strings.xml
@@ -54,6 +54,8 @@
     <!-- Menu item title that moves the selected documents [CHAR LIMIT=24] -->
     <string name="menu_move">Move to\u2026</string>
 
+    <!-- Menu item title that creates a new window in the activity [CHAR LIMIT=24] -->
+    <string name="menu_new_window">New window</string>
     <!-- Menu item title that copies the selected documents to clipboard [CHAR LIMIT=24] -->
     <string name="menu_copy_to_clipboard">Copy</string>
     <!-- Menu item title that pastes files from the clipboard [CHAR LIMIT=24] -->
@@ -81,7 +83,8 @@
     <string name="button_move">Move</string>
     <!-- Button label that hides the error bar [CHAR LIMIT=24] -->
     <string name="button_dismiss">Dismiss</string>
-
+    <string name="button_retry">Try Again</string>
+    
     <!-- Mode that sorts documents by their display name alphabetically [CHAR LIMIT=24] -->
     <string name="sort_name">By name</string>
     <!-- Mode that sorts documents by their last modified time in descending order; most recent first [CHAR LIMIT=24] -->
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 4d0a7eb..a6a45e5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -16,13 +16,6 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
 import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
 import static com.android.documentsui.DirectoryFragment.ANIM_SIDE;
@@ -40,14 +33,11 @@
 import android.net.Uri;
 import android.os.AsyncTask;
 import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
 import android.support.annotation.LayoutRes;
 import android.support.annotation.Nullable;
 import android.util.Log;
-import android.util.SparseArray;
 import android.view.LayoutInflater;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -74,7 +64,6 @@
 import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collection;
-import java.util.HashMap;
 import java.util.List;
 import java.util.concurrent.Executor;
 
@@ -86,10 +75,11 @@
     RootsCache mRoots;
     SearchManager mSearchManager;
     DrawerController mDrawer;
+    boolean mProductivityDevice;
 
+    private final String mTag;
     @LayoutRes
     private int mLayoutId;
-    private final String mTag;
     private DirectoryContainerView mDirectoryContainer;
 
     public abstract void onDocumentPicked(DocumentInfo doc, @Nullable DocumentContext siblings);
@@ -110,6 +100,7 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
+        mProductivityDevice = getResources().getBoolean(R.bool.productivity_device);
         mState = (icicle != null)
                 ? icicle.<State>getParcelable(EXTRA_STATE)
                         : buildState();
@@ -125,22 +116,6 @@
     }
 
     @Override
-    public void onResume() {
-        super.onResume();
-
-        final State state = getDisplayState();
-        final RootInfo root = getCurrentRoot();
-
-        // If we're browsing a specific root, and that root went away, then we
-        // have no reason to hang around
-        if (state.action == State.ACTION_BROWSE && root != null) {
-            if (mRoots.getRootBlocking(root.authority, root.rootId) == null) {
-                finish();
-            }
-        }
-    }
-
-    @Override
     public boolean onCreateOptionsMenu(Menu menu) {
         boolean showMenu = super.onCreateOptionsMenu(menu);
 
@@ -178,8 +153,10 @@
         State state = getDisplayState();
 
         sortSize.setVisible(state.showSize); // Only sort by size when visible
+        fileSize.setVisible(!state.showSize);
         grid.setVisible(state.derivedMode != State.MODE_GRID);
         list.setVisible(state.derivedMode != State.MODE_LIST);
+        advanced.setVisible(!mState.showAdvanced);
         settings.setVisible((root.flags & Root.FLAG_HAS_SETTINGS) != 0);
 
         return shown;
@@ -189,13 +166,17 @@
         State state = new State();
 
         final Intent intent = getIntent();
-        final String action = intent.getAction();
 
         state.localOnly = intent.getBooleanExtra(Intent.EXTRA_LOCAL_ONLY, false);
-        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
-        state.showAdvanced = state.forceAdvanced ||
-                LocalPreferences.getDisplayAdvancedDevices(this);
 
+        state.forceSize = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_FILESIZE, false);
+        state.showSize = state.forceSize || LocalPreferences.getDisplayFileSize(this);
+
+        state.forceAdvanced = intent.getBooleanExtra(DocumentsContract.EXTRA_SHOW_ADVANCED, false);
+        state.showAdvanced = state.forceAdvanced
+                || LocalPreferences.getDisplayAdvancedDevices(this);
+
+        state.initAcceptMimes(intent);
         state.excludedAuthorities = getExcludedAuthorities();
 
         return state;
@@ -219,7 +200,7 @@
         if (mRoots.isRecentsRoot(root)) {
             onCurrentDirectoryChanged(ANIM_SIDE);
         } else {
-            new PickRootTask(root).executeOnExecutor(getCurrentExecutor());
+            new PickRootTask(root).executeOnExecutor(getExecutorForCurrentDirectory());
         }
     }
 
@@ -229,6 +210,7 @@
             switch (item.getItemId()) {
                 case R.id.menu_advanced:
                 case R.id.menu_file_size:
+                case R.id.menu_new_window:
                     break;
                 default:
                     item.setShowAsAction(MenuItem.SHOW_AS_ACTION_ALWAYS);
@@ -384,118 +366,6 @@
         public static String EXTRA_DIRECTORY_COPY = "com.android.documentsui.DIRECTORY_COPY";
     }
 
-    public static class State implements android.os.Parcelable {
-        public int action;
-        public String[] acceptMimes;
-
-        /** Explicit user choice */
-        public int userMode = MODE_UNKNOWN;
-        /** Derived after loader */
-        public int derivedMode = MODE_LIST;
-
-        /** Explicit user choice */
-        public int userSortOrder = SORT_ORDER_UNKNOWN;
-        /** Derived after loader */
-        public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
-
-        public boolean allowMultiple;
-        public boolean showSize;
-        public boolean localOnly ;
-        public boolean forceAdvanced ;
-        public boolean showAdvanced ;
-        public boolean stackTouched ;
-        public boolean restored ;
-        public boolean directoryCopy ;
-        /** Transfer mode for file copy/move operations. */
-        public int transferMode;
-
-        /** Current user navigation stack; empty implies recents. */
-        public DocumentStack stack = new DocumentStack();
-        /** Currently active search, overriding any stack. */
-        public String currentSearch;
-
-        /** Instance state for every shown directory */
-        public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
-
-        /** Currently copying file */
-        public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
-
-        /** Name of the package that started DocsUI */
-        public List<String> excludedAuthorities = new ArrayList<>();
-
-        public static final int ACTION_OPEN = 1;
-        public static final int ACTION_CREATE = 2;
-        public static final int ACTION_GET_CONTENT = 3;
-        public static final int ACTION_OPEN_TREE = 4;
-        public static final int ACTION_MANAGE = 5;
-        public static final int ACTION_BROWSE = 6;
-        public static final int ACTION_BROWSE_ALL = 7;
-        public static final int ACTION_OPEN_COPY_DESTINATION = 8;
-
-        public static final int MODE_UNKNOWN = 0;
-        public static final int MODE_LIST = 1;
-        public static final int MODE_GRID = 2;
-
-        public static final int SORT_ORDER_UNKNOWN = 0;
-        public static final int SORT_ORDER_DISPLAY_NAME = 1;
-        public static final int SORT_ORDER_LAST_MODIFIED = 2;
-        public static final int SORT_ORDER_SIZE = 3;
-
-        @Override
-        public int describeContents() {
-            return 0;
-        }
-
-        @Override
-        public void writeToParcel(Parcel out, int flags) {
-            out.writeInt(action);
-            out.writeInt(userMode);
-            out.writeStringArray(acceptMimes);
-            out.writeInt(userSortOrder);
-            out.writeInt(allowMultiple ? 1 : 0);
-            out.writeInt(showSize ? 1 : 0);
-            out.writeInt(localOnly ? 1 : 0);
-            out.writeInt(forceAdvanced ? 1 : 0);
-            out.writeInt(showAdvanced ? 1 : 0);
-            out.writeInt(stackTouched ? 1 : 0);
-            out.writeInt(restored ? 1 : 0);
-            DurableUtils.writeToParcel(out, stack);
-            out.writeString(currentSearch);
-            out.writeMap(dirState);
-            out.writeList(selectedDocumentsForCopy);
-            out.writeList(excludedAuthorities);
-        }
-
-        public static final Creator<State> CREATOR = new Creator<State>() {
-            @Override
-            public State createFromParcel(Parcel in) {
-                final State state = new State();
-                state.action = in.readInt();
-                state.userMode = in.readInt();
-                state.acceptMimes = in.readStringArray();
-                state.userSortOrder = in.readInt();
-                state.allowMultiple = in.readInt() != 0;
-                state.showSize = in.readInt() != 0;
-                state.localOnly = in.readInt() != 0;
-                state.forceAdvanced = in.readInt() != 0;
-                state.showAdvanced = in.readInt() != 0;
-                state.stackTouched = in.readInt() != 0;
-                state.restored = in.readInt() != 0;
-                DurableUtils.readFromParcel(in, state.stack);
-                state.currentSearch = in.readString();
-                in.readMap(state.dirState, null);
-                in.readList(state.selectedDocumentsForCopy, null);
-                in.readList(state.excludedAuthorities, null);
-                return state;
-            }
-
-            @Override
-            public State[] newArray(int size) {
-                return new State[size];
-            }
-        };
-    }
-
     void setDisplayAdvancedDevices(boolean display) {
         State state = getDisplayState();
         LocalPreferences.setDisplayAdvancedDevices(this, display);
@@ -562,7 +432,7 @@
         return getDisplayState().stack.peek();
     }
 
-    public Executor getCurrentExecutor() {
+    public Executor getExecutorForCurrentDirectory() {
         final DocumentInfo cwd = getCurrentDirectory();
         if (cwd != null && cwd.authority != null) {
             return ProviderExecutor.forAuthority(cwd.authority);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
index f8ec8f1..815fbfe 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CopyService.java
@@ -16,9 +16,11 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
+import android.app.Activity;
 import android.app.IntentService;
 import android.app.Notification;
 import android.app.NotificationManager;
@@ -36,6 +38,7 @@
 import android.os.SystemClock;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.support.design.widget.Snackbar;
 import android.text.format.DateUtils;
 import android.util.Log;
 import android.widget.Toast;
@@ -56,7 +59,6 @@
 
 public class CopyService extends IntentService {
     public static final String TAG = "CopyService";
-    public static final boolean DEBUG = false;
 
     private static final String EXTRA_CANCEL = "com.android.documentsui.CANCEL";
     public static final String EXTRA_SRC_LIST = "com.android.documentsui.SRC_LIST";
@@ -107,10 +109,10 @@
      * @param srcDocs A list of src files to copy.
      * @param dstStack The copy destination stack.
      */
-    public static void start(Context context, List<DocumentInfo> srcDocs, DocumentStack dstStack,
+    public static void start(Activity activity, List<DocumentInfo> srcDocs, DocumentStack dstStack,
             int mode) {
-        final Resources res = context.getResources();
-        final Intent copyIntent = new Intent(context, CopyService.class);
+        final Resources res = activity.getResources();
+        final Intent copyIntent = new Intent(activity, CopyService.class);
         copyIntent.putParcelableArrayListExtra(
                 EXTRA_SRC_LIST, new ArrayList<DocumentInfo>(srcDocs));
         copyIntent.putExtra(EXTRA_STACK, (Parcelable) dstStack);
@@ -118,10 +120,10 @@
 
         int toastMessage = (mode == TRANSFER_MODE_COPY) ? R.plurals.copy_begin
                 : R.plurals.move_begin;
-        Toast.makeText(context,
+        Shared.makeSnackbar(activity,
                 res.getQuantityString(toastMessage, srcDocs.size(), srcDocs.size()),
-                Toast.LENGTH_SHORT).show();
-        context.startService(copyIntent);
+                Snackbar.LENGTH_SHORT).show();
+        activity.startService(copyIntent);
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
index e408e6e..9f44516 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/CreateDirectoryFragment.java
@@ -32,6 +32,7 @@
 import android.os.Bundle;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
+import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.LayoutInflater;
@@ -39,7 +40,6 @@
 import android.widget.EditText;
 import android.widget.TextView;
 import android.widget.TextView.OnEditorActionListener;
-import android.widget.Toast;
 
 import com.android.documentsui.model.DocumentInfo;
 
@@ -147,7 +147,7 @@
                 // Navigate into newly created child
                 mActivity.onDirectoryCreated(result);
             } else {
-                Toast.makeText(mActivity, R.string.create_error, Toast.LENGTH_SHORT).show();
+                Shared.makeSnackbar(mActivity, R.string.create_error, Snackbar.LENGTH_SHORT).show();
             }
 
             mActivity.setPending(false);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
index 1a17b6c..3c6be6e 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryFragment.java
@@ -16,15 +16,15 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE_ALL;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.BaseActivity.State.MODE_GRID;
-import static com.android.documentsui.BaseActivity.State.MODE_LIST;
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.ACTION_BROWSE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_MANAGE;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
@@ -91,17 +91,14 @@
 import android.view.ViewParent;
 import android.widget.ImageView;
 import android.widget.TextView;
-import android.widget.Toast;
 
 import com.android.documentsui.BaseActivity.DocumentContext;
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.MultiSelectManager.Selection;
 import com.android.documentsui.ProviderExecutor.Preemptable;
 import com.android.documentsui.RecentsProvider.StateColumns;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
 
 import com.google.common.collect.Lists;
 
@@ -126,7 +123,6 @@
     public static final int REQUEST_COPY_DESTINATION = 1;
 
     private static final int LOADER_ID = 42;
-    private static final boolean DEBUG = false;
     private static final boolean DEBUG_ENABLE_DND = false;
 
     private static final String EXTRA_TYPE = "type";
@@ -369,21 +365,6 @@
 
             @Override
             public void onLoadFinished(Loader<DirectoryResult> loader, DirectoryResult result) {
-                if (result == null || result.exception != null) {
-                    // onBackPressed does a fragment transaction, which can't be done inside
-                    // onLoadFinished
-                    mHandler.post(new Runnable() {
-                        @Override
-                        public void run() {
-                            final Activity activity = getActivity();
-                            if (activity != null) {
-                                activity.onBackPressed();
-                            }
-                        }
-                    });
-                    return;
-                }
-
                 if (!isAdded()) return;
 
                 mModel.update(result);
@@ -631,7 +612,6 @@
 
         @Override
         public void onItemStateChanged(int position, boolean selected) {
-
             final Cursor cursor = mModel.getItem(position);
             checkNotNull(cursor, "Cursor cannot be null.");
 
@@ -717,8 +697,9 @@
                 return true;
 
             } else if (id == R.id.menu_delete) {
-                deleteDocuments(selection);
+                // Exit selection mode first, so we avoid deselecting deleted documents.
                 mode.finish();
+                deleteDocuments(selection);
                 return true;
 
             } else if (id == R.id.menu_copy_to) {
@@ -727,8 +708,9 @@
                 return true;
 
             } else if (id == R.id.menu_move_to) {
-                transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
+                // Exit selection mode first, so we avoid deselecting deleted documents.
                 mode.finish();
+                transferDocuments(selection, CopyService.TRANSFER_MODE_MOVE);
                 return true;
 
             } else if (id == R.id.menu_copy_to_clipboard) {
@@ -822,8 +804,8 @@
 
         mModel.markForDeletion(selected);
 
-        Activity activity = getActivity();
-        Snackbar.make(this.getView(), message, Snackbar.LENGTH_LONG)
+        final Activity activity = getActivity();
+        Shared.makeSnackbar(activity, message, Snackbar.LENGTH_LONG)
                 .setAction(
                         R.string.undo,
                         new android.view.View.OnClickListener() {
@@ -838,11 +820,11 @@
                                     mModel.undoDeletion();
                                 } else {
                                     mModel.finalizeDeletion(
-                                            new Runnable() {
+                                            new Model.DeletionListener() {
                                                 @Override
-                                                public void run() {
-                                                    Snackbar.make(
-                                                            DirectoryFragment.this.getView(),
+                                                public void onError() {
+                                                    Shared.makeSnackbar(
+                                                            activity,
                                                             R.string.toast_failed_delete,
                                                             Snackbar.LENGTH_LONG)
                                                             .show();
@@ -900,6 +882,29 @@
         }
     }
 
+    void showEmptyView() {
+        mEmptyView.setVisibility(View.VISIBLE);
+        mRecView.setVisibility(View.GONE);
+        TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+        msg.setText(R.string.empty);
+        // No retry button for the empty view.
+        mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+    }
+
+    void showErrorView() {
+        mEmptyView.setVisibility(View.VISIBLE);
+        mRecView.setVisibility(View.GONE);
+        TextView msg = (TextView) mEmptyView.findViewById(R.id.message);
+        msg.setText(R.string.query_error);
+        // TODO: Enable this once the retry button does something.
+        mEmptyView.findViewById(R.id.button_retry).setVisibility(View.GONE);
+    }
+
+    void showRecyclerView() {
+        mEmptyView.setVisibility(View.GONE);
+        mRecView.setVisibility(View.VISIBLE);
+    }
+
     private final class DocumentsAdapter extends RecyclerView.Adapter<DocumentHolder> {
 
         private final Context mContext;
@@ -1239,9 +1244,11 @@
 
     private void copyDocuments(final List<DocumentInfo> docs, final DocumentInfo destination) {
         if (!canCopy(docs, destination)) {
-            Toast.makeText(
+            Shared.makeSnackbar(
                     getActivity(),
-                    R.string.clipboard_files_cannot_paste, Toast.LENGTH_SHORT).show();
+                    R.string.clipboard_files_cannot_paste,
+                    Snackbar.LENGTH_SHORT)
+                    .show();
             return;
         }
 
@@ -1291,10 +1298,10 @@
             void onDocumentsReady(List<DocumentInfo> docs) {
                 mClipper.clipDocuments(docs);
                 Activity activity = getActivity();
-                Toast.makeText(activity,
+                Shared.makeSnackbar(activity,
                         activity.getResources().getQuantityString(
                                 R.plurals.clipboard_files_clipped, docs.size(), docs.size()),
-                                Toast.LENGTH_SHORT).show();
+                                Snackbar.LENGTH_SHORT).show();
             }
         }.execute(items);
     }
@@ -1554,9 +1561,9 @@
     }
 
     private FragmentTuner pickFragmentTuner(final State state) {
-        return state.action == ACTION_BROWSE_ALL
+        return state.action == ACTION_BROWSE
                 ? new FilesTuner()
-                : new DefaultTuner(state);
+                : new DefaultTuner(state.action);
     }
 
     /**
@@ -1593,15 +1600,14 @@
      */
     private static final class DefaultTuner implements FragmentTuner {
 
-        private final State mState;
+        private final boolean mManaging;
 
-        public DefaultTuner(State state) {
-            mState = state;
+        public DefaultTuner(int action) {
+            mManaging = (action == ACTION_MANAGE);
         }
 
         @Override
         public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
-            Preconditions.checkState(mState.action != ACTION_BROWSE_ALL);
 
             final MenuItem open = menu.findItem(R.id.menu_open);
             final MenuItem share = menu.findItem(R.id.menu_share);
@@ -1610,14 +1616,11 @@
             final MenuItem moveTo = menu.findItem(R.id.menu_move_to);
             final MenuItem copyToClipboard = menu.findItem(R.id.menu_copy_to_clipboard);
 
-            final boolean manageOrBrowse = (mState.action == ACTION_MANAGE
-                    || mState.action == ACTION_BROWSE);
-
-            open.setVisible(!manageOrBrowse);
-            share.setVisible(manageOrBrowse);
-            delete.setVisible(manageOrBrowse && canDelete);
+            open.setVisible(!mManaging);
+            share.setVisible(mManaging);
+            delete.setVisible(mManaging && canDelete);
             // Disable copying from the Recents view.
-            copyTo.setVisible(manageOrBrowse && dirType != TYPE_RECENT_OPEN);
+            copyTo.setVisible(mManaging && dirType != TYPE_RECENT_OPEN);
             moveTo.setVisible(SystemProperties.getBoolean("debug.documentsui.enable_move", false));
 
             // Only shown in files mode.
@@ -1634,6 +1637,7 @@
     private static final class FilesTuner implements FragmentTuner {
         @Override
         public void updateActionMenu(Menu menu, int dirType, boolean canDelete) {
+
             menu.findItem(R.id.menu_share).setVisible(true);
             menu.findItem(R.id.menu_delete).setVisible(canDelete);
             menu.findItem(R.id.menu_copy_to_clipboard).setVisible(true);
@@ -1861,9 +1865,9 @@
          * @param view The view which will be used to interact with the user (e.g. surfacing
          * snackbars) for errors, info, etc.
          */
-        void finalizeDeletion(Runnable errorCallback) {
+        void finalizeDeletion(DeletionListener listener) {
             final ContentResolver resolver = mContext.getContentResolver();
-            DeleteFilesTask task = new DeleteFilesTask(resolver, errorCallback);
+            DeleteFilesTask task = new DeleteFilesTask(resolver, listener);
             task.execute();
         }
 
@@ -1873,16 +1877,16 @@
          */
         private class DeleteFilesTask extends AsyncTask<Void, Void, List<DocumentInfo>> {
             private ContentResolver mResolver;
-            private Runnable mErrorCallback;
+            private DeletionListener mListener;
 
             /**
              * @param resolver A ContentResolver for performing the actual file deletions.
              * @param errorCallback A Runnable that is executed in the event that one or more errors
              *     occured while copying files.  Execution will occur on the UI thread.
              */
-            public DeleteFilesTask(ContentResolver resolver, Runnable errorCallback) {
+            public DeleteFilesTask(ContentResolver resolver, DeletionListener listener) {
                 mResolver = resolver;
-                mErrorCallback = errorCallback;
+                mListener = listener;
             }
 
             @Override
@@ -1916,15 +1920,29 @@
 
                 if (hadTrouble) {
                     // TODO show which files failed? b/23720103
-                    mErrorCallback.run();
+                    mListener.onError();
                     if (DEBUG) Log.d(TAG, "Deletion task completed.  Some deletions failed.");
                 } else {
                     if (DEBUG) Log.d(TAG, "Deletion task completed successfully.");
                 }
                 mMarkedForDeletion.clear();
+
+                mListener.onCompletion();
             }
         }
 
+        static class DeletionListener {
+            /**
+             * Called when deletion has completed (regardless of whether an error occurred).
+             */
+            void onCompletion() {}
+
+            /**
+             * Called at the end of a deletion operation that produced one or more errors.
+             */
+            void onError() {}
+        }
+
         void addUpdateListener(UpdateListener listener) {
             checkState(mUpdateListener == null);
             mUpdateListener = listener;
@@ -1955,21 +1973,16 @@
             mProgressBar.setVisibility(model.isLoading() ? View.VISIBLE : View.GONE);
 
             if (model.isEmpty()) {
-                mEmptyView.setVisibility(View.VISIBLE);
-                mRecView.setVisibility(View.GONE);
+                showEmptyView();
             } else {
-                mEmptyView.setVisibility(View.GONE);
-                mRecView.setVisibility(View.VISIBLE);
+                showRecyclerView();
+                mAdapter.notifyDataSetChanged();
             }
-
-            mAdapter.notifyDataSetChanged();
         }
 
         @Override
         public void onModelUpdateFailed(Exception e) {
-            // TODO: deal with catastrophic update failures
-            String error = getString(R.string.query_error);
-            mAdapter.notifyDataSetChanged();
+            showErrorView();
         }
     }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 0edb241..bb82b38 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -16,12 +16,12 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.MODE_UNKNOWN;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_UNKNOWN;
 import static com.android.documentsui.model.DocumentInfo.getCursorInt;
 
 import android.content.AsyncTaskLoader;
@@ -37,7 +37,6 @@
 import android.provider.DocumentsContract.Document;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.RecentsProvider.StateColumns;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
index 4893652..000b92a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryView.java
@@ -18,9 +18,9 @@
 
 import android.content.Context;
 import android.util.AttributeSet;
-import android.widget.FrameLayout;
+import android.widget.LinearLayout;
 
-public class DirectoryView extends FrameLayout {
+public class DirectoryView extends LinearLayout {
     private float mPosition = 0f;
 
     private int mWidth;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
index 8b2b4f2..f6ded4b 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentsActivity.java
@@ -16,19 +16,16 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_BROWSE;
-import static com.android.documentsui.BaseActivity.State.ACTION_CREATE;
-import static com.android.documentsui.BaseActivity.State.ACTION_GET_CONTENT;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_COPY_DESTINATION;
-import static com.android.documentsui.BaseActivity.State.ACTION_OPEN_TREE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_CREATE;
+import static com.android.documentsui.State.ACTION_GET_CONTENT;
+import static com.android.documentsui.State.ACTION_OPEN;
+import static com.android.documentsui.State.ACTION_OPEN_COPY_DESTINATION;
+import static com.android.documentsui.State.ACTION_OPEN_TREE;
 
 import android.app.Activity;
 import android.app.Fragment;
 import android.app.FragmentManager;
-import android.content.ActivityNotFoundException;
 import android.content.ClipData;
 import android.content.ComponentName;
 import android.content.ContentProviderClient;
@@ -44,7 +41,7 @@
 import android.os.Bundle;
 import android.os.Parcelable;
 import android.provider.DocumentsContract;
-import android.provider.DocumentsContract.Root;
+import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.Menu;
 import android.view.MenuItem;
@@ -52,7 +49,6 @@
 import android.view.WindowManager;
 import android.widget.BaseAdapter;
 import android.widget.Spinner;
-import android.widget.Toast;
 import android.widget.Toolbar;
 
 import com.android.documentsui.RecentsProvider.RecentColumns;
@@ -87,7 +83,7 @@
         super.onCreate(icicle);
 
         final Resources res = getResources();
-        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog) && mState.action != ACTION_BROWSE;
+        mShowAsDialog = res.getBoolean(R.bool.show_as_dialog);
 
         if (!mShowAsDialog) {
             setTheme(R.style.DocumentsNonDialogTheme);
@@ -123,14 +119,6 @@
 
         setActionBar(mToolbar);
 
-        // Hide roots when we're managing a specific root
-        if (mState.action == ACTION_BROWSE) {
-            mDrawer.lockClosed();
-            if (mShowAsDialog) {
-                findViewById(R.id.container_roots).setVisibility(View.GONE);
-            }
-        }
-
         if (mState.action == ACTION_CREATE) {
             final String mimeType = getIntent().getType();
             final String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);
@@ -156,12 +144,7 @@
             // In this case, we set the activity title in AsyncTask.onPostExecute().  To prevent
             // talkback from reading aloud the default title, we clear it here.
             setTitle("");
-            if (mState.action == ACTION_BROWSE) {
-                final Uri rootUri = getIntent().getData();
-                new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
-            } else {
-                new RestoreStackTask().execute();
-            }
+            new RestoreStackTask().execute();
         } else {
             onCurrentDirectoryChanged(ANIM_NONE);
         }
@@ -181,8 +164,6 @@
             state.action = ACTION_GET_CONTENT;
         } else if (Intent.ACTION_OPEN_DOCUMENT_TREE.equals(action)) {
             state.action = ACTION_OPEN_TREE;
-        } else if (DocumentsContract.ACTION_BROWSE_DOCUMENT_ROOT.equals(action)) {
-            state.action = ACTION_BROWSE;
         } else if (DocumentsIntent.ACTION_OPEN_COPY_DESTINATION.equals(action)) {
             state.action = ACTION_OPEN_COPY_DESTINATION;
         }
@@ -192,20 +173,6 @@
                     Intent.EXTRA_ALLOW_MULTIPLE, false);
         }
 
-        if (state.action == ACTION_BROWSE) {
-            state.acceptMimes = new String[] { "*/*" };
-            state.allowMultiple = true;
-        } else if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
-            state.acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
-        } else {
-            state.acceptMimes = new String[] { intent.getType() };
-        }
-
-        if (state.action == ACTION_BROWSE) {
-            state.showSize = true;
-        } else {
-            state.showSize = LocalPreferences.getDisplayFileSize(this);
-        }
         if (state.action == ACTION_OPEN_COPY_DESTINATION) {
             state.directoryCopy = intent.getBooleanExtra(
                     BaseActivity.DocumentsIntent.EXTRA_DIRECTORY_COPY, false);
@@ -357,11 +324,7 @@
         final MenuItem fileSize = menu.findItem(R.id.menu_file_size);
         final MenuItem settings = menu.findItem(R.id.menu_settings);
 
-        // File size is locked visible for browse because that is the action triggered by Settings,
-        // where the user is trying to find large files to clean up.
-        // TODO: instead of setting this according to the action, use a local preference, but
-        // provide a @hide extra to let callers like Settings force-enable size visibility.
-        boolean fileSizeVisible = mState.action != ACTION_BROWSE;
+        boolean fileSizeVisible = mState.showSize && !mState.forceSize;
         if (mState.action == ACTION_CREATE
                 || mState.action == ACTION_OPEN_TREE
                 || mState.action == ACTION_OPEN_COPY_DESTINATION) {
@@ -383,11 +346,9 @@
             createDir.setVisible(false);
         }
 
-        advanced.setVisible(mState.action != ACTION_BROWSE && !mState.forceAdvanced);
+        advanced.setVisible(!mState.forceAdvanced);
         fileSize.setVisible(fileSizeVisible);
-
-        settings.setVisible(mState.action == ACTION_BROWSE
-                && (root.flags & Root.FLAG_HAS_SETTINGS) != 0);
+        settings.setVisible(false);
 
         return true;
     }
@@ -446,11 +407,11 @@
     }
 
     void onSaveRequested(DocumentInfo replaceTarget) {
-        new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getCurrentExecutor());
+        new ExistingFinishTask(replaceTarget.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
     }
 
     void onSaveRequested(String mimeType, String displayName) {
-        new CreateFinishTask(mimeType, displayName).executeOnExecutor(getCurrentExecutor());
+        new CreateFinishTask(mimeType, displayName).executeOnExecutor(getExecutorForCurrentDirectory());
     }
 
     @Override
@@ -466,21 +427,10 @@
             openDirectory(doc);
         } else if (mState.action == ACTION_OPEN || mState.action == ACTION_GET_CONTENT) {
             // Explicit file picked, return
-            new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getCurrentExecutor());
+            new ExistingFinishTask(doc.derivedUri).executeOnExecutor(getExecutorForCurrentDirectory());
         } else if (mState.action == ACTION_CREATE) {
             // Replace selected file
             SaveFragment.get(fm).setReplaceTarget(doc);
-        } else if (mState.action == ACTION_BROWSE) {
-            // Go straight to viewing
-            final Intent view = new Intent(Intent.ACTION_VIEW);
-            view.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-            view.setData(doc.derivedUri);
-
-            try {
-                startActivity(view);
-            } catch (ActivityNotFoundException ex) {
-                Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
-            }
         }
     }
 
@@ -492,7 +442,7 @@
             for (int i = 0; i < size; i++) {
                 uris[i] = docs.get(i).derivedUri;
             }
-            new ExistingFinishTask(uris).executeOnExecutor(getCurrentExecutor());
+            new ExistingFinishTask(uris).executeOnExecutor(getExecutorForCurrentDirectory());
         }
     }
 
@@ -507,7 +457,7 @@
             // Should not be reached.
             throw new IllegalStateException("Invalid mState.action.");
         }
-        new PickFinishTask(result).executeOnExecutor(getCurrentExecutor());
+        new PickFinishTask(result).executeOnExecutor(getExecutorForCurrentDirectory());
     }
 
     @Override
@@ -661,8 +611,8 @@
             if (result != null) {
                 onTaskFinished(result);
             } else {
-                Toast.makeText(DocumentsActivity.this, R.string.save_error, Toast.LENGTH_SHORT)
-                        .show();
+                Shared.makeSnackbar(
+                    DocumentsActivity.this, R.string.save_error, Snackbar.LENGTH_SHORT).show();
             }
 
             setPending(false);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index c1362c8..df803fb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -16,8 +16,10 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.internal.util.Preconditions.checkArgument;
+import static com.android.internal.util.Preconditions.checkState;
 
 import android.app.Activity;
 import android.app.FragmentManager;
@@ -25,12 +27,11 @@
 import android.content.ClipData;
 import android.content.ContentResolver;
 import android.content.ContentValues;
-import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
-import android.provider.DocumentsContract;
 import android.support.annotation.Nullable;
+import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.KeyEvent;
 import android.view.Menu;
@@ -38,7 +39,6 @@
 import android.view.View;
 import android.widget.BaseAdapter;
 import android.widget.Spinner;
-import android.widget.Toast;
 import android.widget.Toolbar;
 
 import com.android.documentsui.RecentsProvider.ResumeColumns;
@@ -46,7 +46,6 @@
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
 import com.android.documentsui.model.RootInfo;
-import com.android.internal.util.Preconditions;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -58,7 +57,6 @@
 public class FilesActivity extends BaseActivity {
 
     public static final String TAG = "FilesActivity";
-    static final boolean DEBUG = false;
 
     private Toolbar mToolbar;
     private Spinner mToolbarStack;
@@ -74,8 +72,6 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        final Context context = this;
-
         mToolbar = (Toolbar) findViewById(R.id.toolbar);
 
         mStackAdapter = new StackAdapter();
@@ -90,10 +86,19 @@
 
         RootsFragment.show(getFragmentManager(), null);
         if (!mState.restored) {
-            new RestoreStackTask().execute();
+            Intent intent = getIntent();
+            Uri rootUri = intent.getData();
+
+            // If we've got a specific root to display, restore that root using a dedicated
+            // authority. That way a misbehaving provider won't result in an ANR.
+            if (rootUri != null && !LauncherActivity.isLaunchUri(rootUri)) {
+                new RestoreRootTask(rootUri).executeOnExecutor(
+                        ProviderExecutor.forAuthority(rootUri.getAuthority()));
+            } else {
+                new RestoreStackTask().execute();
+            }
 
             // Show a failure dialog if there was a failed operation.
-            final Intent intent = getIntent();
             final DocumentStack dstStack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
             final int failure = intent.getIntExtra(CopyService.EXTRA_FAILURE, 0);
             final int transferMode = intent.getIntExtra(CopyService.EXTRA_TRANSFER_MODE,
@@ -115,22 +120,16 @@
 
         final Intent intent = getIntent();
 
-        state.action = State.ACTION_BROWSE_ALL;
-        state.acceptMimes = new String[] { intent.getType() };
+        state.action = State.ACTION_BROWSE;
         state.allowMultiple = true;
 
-        // These options are specific to the DocumentsActivity.
-        Preconditions.checkArgument(
-                !intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
-        Preconditions.checkArgument(
-                !intent.hasExtra(DocumentsContract.EXTRA_SHOW_ADVANCED));
-
-        state.showAdvanced = LocalPreferences.getDisplayAdvancedDevices(this);
-        state.showSize = LocalPreferences.getDisplayFileSize(this);
+        // Options specific to the DocumentsActivity.
+        checkArgument(!intent.hasExtra(Intent.EXTRA_LOCAL_ONLY));
 
         final DocumentStack stack = intent.getParcelableExtra(CopyService.EXTRA_STACK);
-        if (stack != null)
+        if (stack != null) {
             state.stack = stack;
+        }
 
         return state;
     }
@@ -142,6 +141,21 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+
+        final RootInfo root = getCurrentRoot();
+
+        // If we're browsing a specific root, and that root went away, then we
+        // have no reason to hang around.
+        // TODO: Rather than just disappearing, maybe we should inform
+        // the user what has happened, let them close us. Less surprising.
+        if (mRoots.getRootBlocking(root.authority, root.rootId) == null) {
+            finish();
+        }
+    }
+
+    @Override
     public void updateActionBar() {
         final RootInfo root = getCurrentRoot();
 
@@ -197,17 +211,22 @@
         menu.findItem(R.id.menu_file_size).setVisible(true);
         menu.findItem(R.id.menu_advanced).setVisible(true);
 
-        final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
         final MenuItem createDir = menu.findItem(R.id.menu_create_dir);
-        final MenuItem settings = menu.findItem(R.id.menu_settings);
+        final MenuItem newWindow = menu.findItem(R.id.menu_new_window);
+        final MenuItem pasteFromCb = menu.findItem(R.id.menu_paste_from_clipboard);
 
         boolean canCreateDir = canCreateDirectory();
 
         createDir.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
         createDir.setVisible(canCreateDir);
+        createDir.setEnabled(canCreateDir);
 
-        pasteFromCb.setVisible(true);
+        newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+        newWindow.setVisible(mProductivityDevice);
+        newWindow.setEnabled(mProductivityDevice);
+
         pasteFromCb.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
+        pasteFromCb.setVisible(true);
         pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
 
         return shown;
@@ -215,12 +234,19 @@
 
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
-        final int id = item.getItemId();
-        if (id == R.id.menu_paste_from_clipboard) {
-            DirectoryFragment dir = DirectoryFragment.get(getFragmentManager());
-            dir = DirectoryFragment.get(getFragmentManager());
-            dir.pasteFromClipboard();
-            return true;
+        switch (item.getItemId()) {
+            case R.id.menu_create_dir:
+                checkState(canCreateDirectory());
+                showCreateDirectoryDialog();
+                return true;
+            case R.id.menu_new_window:
+                startActivity(LauncherActivity.createLaunchIntent(this));
+                return true;
+            case R.id.menu_paste_from_clipboard:
+                DirectoryFragment dir = DirectoryFragment.get(getFragmentManager());
+                dir = DirectoryFragment.get(getFragmentManager());
+                dir.pasteFromClipboard();
+                return true;
         }
 
         return super.onOptionsItemSelected(item);
@@ -296,7 +322,7 @@
         try {
             startActivity(intent);
         } catch (ActivityNotFoundException ex2) {
-            Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+            Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT).show();
         }
     }
 
@@ -308,19 +334,13 @@
                 dir = DirectoryFragment.get(getFragmentManager());
                 dir.selectAllFiles();
                 return true;
-            case KeyEvent.KEYCODE_N:
-                if (event.isShiftPressed() && canCreateDirectory()) {
-                    showCreateDirectoryDialog();
-                    return true;
-                }
             case KeyEvent.KEYCODE_C:
                 // TODO: Should be statically bound using alphabeticShortcut. See b/21330356.
                 dir = DirectoryFragment.get(getFragmentManager());
                 dir.copySelectedToClipboard();
-                // TODO: Cancel action mode in directory fragment.
         }
 
-        return super.onKeyUp(keyCode, event);
+        return super.onKeyShortcut(keyCode, event);
     }
 
     @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
index ec1cb1d..a1213d2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/IconUtils.java
@@ -222,7 +222,7 @@
                 return context.getDrawable(R.drawable.ic_doc_album);
             }
 
-            if (mode == BaseActivity.State.MODE_GRID) {
+            if (mode == State.MODE_GRID) {
                 return context.getDrawable(R.drawable.ic_grid_folder);
             } else {
                 return context.getDrawable(R.drawable.ic_doc_folder);
diff --git a/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
new file mode 100644
index 0000000..c29937d
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/LauncherActivity.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.documentsui;
+
+import android.app.Activity;
+import android.app.ActivityManager;
+import android.app.ActivityManager.AppTask;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.support.annotation.Nullable;
+
+import java.util.List;
+
+/**
+ * Provides FilesActivity task grouping support. This allows multiple FilesActivities to be
+ * launched (a behavior imparted by way of {@code documentLaunchMode="intoExisting"} and
+ * our use of pseudo document {@link Uri}s. This also lets us move an existing task
+ * to the foreground when a suitable task exists.
+ *
+ * Requires that {@code documentLaunchMode="intoExisting"} be set on target activity.
+ *
+ */
+public class LauncherActivity extends Activity {
+
+    public static final String LAUNCH_CONTROL_AUTHORITY = "com.android.documentsui.launchControl";
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        ActivityManager activities = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
+        List<AppTask> tasks = activities.getAppTasks();
+
+        AppTask raiseTask = null;
+        for (AppTask task : tasks) {
+            Uri taskUri = task.getTaskInfo().baseIntent.getData();
+            if (taskUri != null && isLaunchUri(taskUri)) {
+                raiseTask = task;
+            }
+        }
+
+        if (raiseTask == null) {
+            launchFilesTask();
+        } else {
+            raiseFilesTask(activities, raiseTask.getTaskInfo());
+        }
+
+        finish();
+    }
+
+    private void launchFilesTask() {
+        Intent intent = createLaunchIntent(this);
+        startActivity(intent);
+    }
+
+    private void raiseFilesTask(ActivityManager activities, RecentTaskInfo task) {
+        activities.moveTaskToFront(task.id, 0);
+    }
+
+    static Intent createLaunchIntent(Context context) {
+        Intent intent = new Intent(context, FilesActivity.class);
+        intent.setData(buildLaunchUri());
+        return intent;
+    }
+
+    private static Uri buildLaunchUri() {
+        return new Uri.Builder()
+                .authority(LAUNCH_CONTROL_AUTHORITY)
+                .fragment(String.valueOf(System.currentTimeMillis()))
+                .build();
+    }
+
+    static boolean isLaunchUri(@Nullable Uri uri) {
+        return uri != null && LAUNCH_CONTROL_AUTHORITY.equals(uri.getAuthority());
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
index 798992b..ed7333d 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/ManageRootActivity.java
@@ -16,9 +16,8 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.ACTION_MANAGE;
-import static com.android.documentsui.DirectoryFragment.ANIM_DOWN;
 import static com.android.documentsui.DirectoryFragment.ANIM_NONE;
+import static com.android.documentsui.State.ACTION_MANAGE;
 
 import android.app.Activity;
 import android.app.Fragment;
@@ -32,12 +31,12 @@
 import android.net.Uri;
 import android.os.Bundle;
 import android.provider.DocumentsContract;
+import android.support.design.widget.Snackbar;
 import android.util.Log;
 import android.view.Menu;
 import android.view.View;
 import android.widget.BaseAdapter;
 import android.widget.Spinner;
-import android.widget.Toast;
 import android.widget.Toolbar;
 
 import com.android.documentsui.RecentsProvider.ResumeColumns;
@@ -87,7 +86,7 @@
             // talkback from reading aloud the default title, we clear it here.
             setTitle("");
             final Uri rootUri = getIntent().getData();
-            new RestoreRootTask(rootUri).executeOnExecutor(getCurrentExecutor());
+            new RestoreRootTask(rootUri).executeOnExecutor(getExecutorForCurrentDirectory());
         } else {
             onCurrentDirectoryChanged(ANIM_NONE);
         }
@@ -185,7 +184,8 @@
                 try {
                     startActivity(view);
                 } catch (ActivityNotFoundException ex2) {
-                    Toast.makeText(this, R.string.toast_no_application, Toast.LENGTH_SHORT).show();
+                    Shared.makeSnackbar(this, R.string.toast_no_application, Snackbar.LENGTH_SHORT)
+                            .show();
                 }
             }
         }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
index 5839943..858fb42 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/MultiSelectManager.java
@@ -365,8 +365,8 @@
             // To make this more correct, we'd need to update the Ranger class to return
             // information about what has changed.
             notifySelectionChanged();
-        } else if (toggleSelection(input.getItemPosition())) {
-            notifySelectionChanged();
+        } else {
+            toggleSelection(input.getItemPosition());
         }
     }
 
@@ -375,14 +375,13 @@
      * a new Ranger (range selection manager) at that point is created.
      *
      * @param position
-     * @return True if state changed.
      */
-    private boolean toggleSelection(int position) {
+    private void toggleSelection(int position) {
         // Position may be special "no position" during certain
         // transitional phases. If so, skip handling of the event.
         if (position == RecyclerView.NO_POSITION) {
             if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
-            return false;
+            return;
         }
 
         boolean changed = false;
@@ -391,7 +390,7 @@
         } else {
             boolean canSelect = notifyBeforeItemStateChange(position, true);
             if (!canSelect) {
-                return false;
+                return;
             }
             if (mSingleSelect && !mSelection.isEmpty()) {
                 clearSelectionQuietly();
@@ -407,7 +406,9 @@
             changed = true;
         }
 
-        return changed;
+        if (changed) {
+            notifySelectionChanged();
+        }
     }
 
     /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
index 5f6a5e9..48e28dc 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/PickFragment.java
@@ -21,7 +21,6 @@
 import android.app.FragmentManager;
 import android.app.FragmentTransaction;
 import android.os.Bundle;
-import android.text.TextUtils;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
@@ -29,8 +28,6 @@
 
 import com.android.documentsui.model.DocumentInfo;
 
-import java.util.Locale;
-
 /**
  * Display pick confirmation bar, usually for selecting a directory.
  */
@@ -93,7 +90,7 @@
     };
 
     /**
-     * @param action Which action defined in BaseActivity.State is the picker shown for.
+     * @param action Which action defined in State is the picker shown for.
      */
     public void setPickTarget(int action, int transferMode, DocumentInfo pickTarget) {
         mAction = action;
@@ -109,11 +106,11 @@
      */
     private void updateView() {
         switch (mAction) {
-            case BaseActivity.State.ACTION_OPEN_TREE:
+            case State.ACTION_OPEN_TREE:
                 mPick.setText(R.string.button_select);
                 mCancel.setVisibility(View.GONE);
                 break;
-            case BaseActivity.State.ACTION_OPEN_COPY_DESTINATION:
+            case State.ACTION_OPEN_COPY_DESTINATION:
                 mPick.setText(R.string.button_copy);
                 mCancel.setVisibility(View.VISIBLE);
                 break;
@@ -123,7 +120,7 @@
         }
 
         if (mPickTarget != null && (
-                mAction == BaseActivity.State.ACTION_OPEN_TREE ||
+                mAction == State.ACTION_OPEN_TREE ||
                 mPickTarget.isCreateSupported())) {
             mContainer.setVisibility(View.VISIBLE);
         } else {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
index 4685c41..607cb95 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/QuickViewIntentBuilder.java
@@ -16,6 +16,8 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.Shared.TAG;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
 import android.content.ClipData;
@@ -38,9 +40,6 @@
  */
 final class QuickViewIntentBuilder {
 
-    private static final String TAG = "QvIntentBuilder";
-    private static final boolean DEBUG = false;
-
     private final DocumentInfo mDocument;
     private final DocumentContext mContext;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
index 1a7095a..c2b64fb 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentLoader.java
@@ -16,8 +16,9 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
 
 import android.app.ActivityManager;
 import android.content.AsyncTaskLoader;
@@ -34,7 +35,6 @@
 import android.text.format.DateUtils;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 
 import com.google.common.util.concurrent.AbstractFuture;
@@ -53,8 +53,6 @@
 import java.util.concurrent.TimeUnit;
 
 public class RecentLoader extends AsyncTaskLoader<DirectoryResult> {
-    private static final boolean DEBUG = false;
-
     // TODO: clean up cursor ownership so background thread doesn't traverse
     // previously returned cursors for filtering/sorting; this currently races
     // with the UI thread.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
index 6811331..cf682fa 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsCreateFragment.java
@@ -45,7 +45,6 @@
 import android.widget.ImageView;
 import android.widget.TextView;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.RecentsProvider.RecentColumns;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
index f6e4349..82eb732 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RecentsProvider.java
@@ -39,6 +39,7 @@
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.DurableUtils;
 import com.android.internal.util.Predicate;
+
 import com.google.android.collect.Sets;
 
 import libcore.io.IoUtils;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
index 05f7d8d..de35cef 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsCache.java
@@ -16,6 +16,7 @@
 
 package com.android.documentsui;
 
+import static com.android.documentsui.Shared.DEBUG;
 import static com.android.documentsui.Shared.TAG;
 
 import android.content.ContentProviderClient;
@@ -34,12 +35,11 @@
 import android.os.SystemClock;
 import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Root;
+import android.support.annotation.VisibleForTesting;
 import android.util.Log;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 import com.android.internal.annotations.GuardedBy;
-import android.support.annotation.VisibleForTesting;
 
 import com.google.common.collect.ArrayListMultimap;
 import com.google.common.collect.Multimap;
@@ -58,8 +58,6 @@
  * Cache of known storage backends and their roots.
  */
 public class RootsCache {
-    private static final boolean LOGD = false;
-
     public static final Uri sNotificationUri = Uri.parse(
             "content://com.android.documentsui.roots/");
 
@@ -91,7 +89,7 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            if (LOGD) Log.d(TAG, "Updating roots due to change at " + uri);
+            if (DEBUG) Log.d(TAG, "Updating roots due to change at " + uri);
             updateAuthorityAsync(uri.getAuthority());
         }
     }
@@ -148,7 +146,7 @@
         final ContentResolver resolver = mContext.getContentResolver();
         synchronized (mLock) {
             for (String authority : mStoppedAuthorities) {
-                if (LOGD) Log.d(TAG, "Loading stopped authority " + authority);
+                if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
                 mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
             }
             mStoppedAuthorities.clear();
@@ -199,7 +197,8 @@
             }
 
             final long delta = SystemClock.elapsedRealtime() - start;
-            Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms");
+            if (DEBUG)
+                Log.d(TAG, "Update found " + mTaskRoots.size() + " roots in " + delta + "ms");
             synchronized (mLock) {
                 mRoots = mTaskRoots;
                 mStoppedAuthorities = mTaskStoppedAuthorities;
@@ -213,7 +212,7 @@
             // Ignore stopped packages for now; we might query them
             // later during UI interaction.
             if ((info.applicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0) {
-                if (LOGD) Log.d(TAG, "Ignoring stopped authority " + info.authority);
+                if (DEBUG) Log.d(TAG, "Ignoring stopped authority " + info.authority);
                 mTaskStoppedAuthorities.add(info.authority);
                 return;
             }
@@ -223,7 +222,7 @@
             if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
                 synchronized (mLock) {
                     if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
-                        if (LOGD) Log.d(TAG, "Used cached roots for " + info.authority);
+                        if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority);
                         cacheHit = true;
                     }
                 }
@@ -241,7 +240,7 @@
      * Bring up requested provider and query for all active roots.
      */
     private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) {
-        if (LOGD) Log.d(TAG, "Loading roots for " + authority);
+        if (DEBUG) Log.d(TAG, "Loading roots for " + authority);
 
         synchronized (mObservedAuthorities) {
             if (mObservedAuthorities.add(authority)) {
@@ -370,10 +369,13 @@
             // Exclude downloads roots that don't support directory creation
             // TODO: Add flag to check the root supports directory creation or not.
             if (state.directoryCopy && root.isDownloads()) continue;
-            // Only show empty roots when creating
-            if ((state.action != State.ACTION_CREATE ||
-                 state.action != State.ACTION_OPEN_TREE ||
-                 state.action != State.ACTION_OPEN_COPY_DESTINATION) && empty) continue;
+
+            // Only show empty roots when creating, or in browse mode.
+            if (empty && (state.action == State.ACTION_OPEN
+                    || state.action == State.ACTION_GET_CONTENT)) {
+                if (DEBUG) Log.i(TAG, "Skipping empty root: " + root);
+                continue;
+            }
 
             // Only include roots that serve requested content
             final boolean overlap =
@@ -385,7 +387,7 @@
 
             // Exclude roots from the calling package.
             if (state.excludedAuthorities.contains(root.authority)) {
-                if (LOGD) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
+                if (DEBUG) Log.d(TAG, "Excluding root " + root.authority + " from calling package.");
                 continue;
             }
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index c02184b..c98da47 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -41,7 +41,6 @@
 import android.widget.ListView;
 import android.widget.TextView;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.RootInfo;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
index 49651b4..c81377a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsLoader.java
@@ -19,7 +19,6 @@
 import android.content.AsyncTaskLoader;
 import android.content.Context;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 
 import java.util.Collection;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/Shared.java b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
index 0c1ebc1..29bcd24 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/Shared.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/Shared.java
@@ -16,13 +16,18 @@
 
 package com.android.documentsui;
 
+import static com.android.internal.util.Preconditions.checkNotNull;
+
+import android.app.Activity;
 import android.content.Context;
+import android.support.design.widget.Snackbar;
+import android.view.View;
 
 /**
  * @hide
  */
 public final class Shared {
-    public static final boolean DEBUG = false;
+    public static final boolean DEBUG = true;
     public static final String TAG = "Documents";
 
     /**
@@ -31,4 +36,14 @@
     public static final String getQuantityString(Context context, int resourceId, int quantity) {
         return context.getResources().getQuantityString(resourceId, quantity, quantity);
     }
+
+    public static final Snackbar makeSnackbar(Activity activity, int messageId, int duration) {
+        return makeSnackbar(activity, activity.getResources().getText(messageId), duration);
+    }
+
+    public static final Snackbar makeSnackbar(Activity activity, CharSequence message, int duration)
+    {
+        final View view = checkNotNull(activity.findViewById(R.id.coordinator_layout));
+        return Snackbar.make(view, message, duration);
+    }
 }
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
index 3ec3d1c..6698ff1 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SortingCursorWrapper.java
@@ -16,9 +16,9 @@
 
 package com.android.documentsui;
 
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_DISPLAY_NAME;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_LAST_MODIFIED;
-import static com.android.documentsui.BaseActivity.State.SORT_ORDER_SIZE;
+import static com.android.documentsui.State.SORT_ORDER_DISPLAY_NAME;
+import static com.android.documentsui.State.SORT_ORDER_LAST_MODIFIED;
+import static com.android.documentsui.State.SORT_ORDER_SIZE;
 import static com.android.documentsui.model.DocumentInfo.getCursorLong;
 import static com.android.documentsui.model.DocumentInfo.getCursorString;
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
new file mode 100644
index 0000000..4306a0e
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -0,0 +1,153 @@
+/*
+ * Copyright (C) 2013 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.documentsui;
+
+import android.content.Intent;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.util.SparseArray;
+
+import com.android.documentsui.model.DocumentInfo;
+import com.android.documentsui.model.DocumentStack;
+import com.android.documentsui.model.DurableUtils;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+public class State implements android.os.Parcelable {
+    public int action;
+    public String[] acceptMimes;
+
+    /** Explicit user choice */
+    public int userMode = MODE_UNKNOWN;
+    /** Derived after loader */
+    public int derivedMode = MODE_LIST;
+
+    /** Explicit user choice */
+    public int userSortOrder = SORT_ORDER_UNKNOWN;
+    /** Derived after loader */
+    public int derivedSortOrder = SORT_ORDER_DISPLAY_NAME;
+
+    public boolean allowMultiple;
+    public boolean forceSize;
+    public boolean showSize;
+    public boolean localOnly;
+    public boolean forceAdvanced;
+    public boolean showAdvanced;
+    public boolean stackTouched;
+    public boolean restored;
+    public boolean directoryCopy;
+    /** Transfer mode for file copy/move operations. */
+    public int transferMode;
+
+    /** Current user navigation stack; empty implies recents. */
+    public DocumentStack stack = new DocumentStack();
+    /** Currently active search, overriding any stack. */
+    public String currentSearch;
+
+    /** Instance state for every shown directory */
+    public HashMap<String, SparseArray<Parcelable>> dirState = new HashMap<>();
+
+    /** Currently copying file */
+    public List<DocumentInfo> selectedDocumentsForCopy = new ArrayList<DocumentInfo>();
+
+    /** Name of the package that started DocsUI */
+    public List<String> excludedAuthorities = new ArrayList<>();
+
+    public static final int ACTION_OPEN = 1;
+    public static final int ACTION_CREATE = 2;
+    public static final int ACTION_GET_CONTENT = 3;
+    public static final int ACTION_OPEN_TREE = 4;
+    public static final int ACTION_MANAGE = 5;
+    public static final int ACTION_BROWSE = 6;
+    public static final int ACTION_OPEN_COPY_DESTINATION = 8;
+
+    public static final int MODE_UNKNOWN = 0;
+    public static final int MODE_LIST = 1;
+    public static final int MODE_GRID = 2;
+
+    public static final int SORT_ORDER_UNKNOWN = 0;
+    public static final int SORT_ORDER_DISPLAY_NAME = 1;
+    public static final int SORT_ORDER_LAST_MODIFIED = 2;
+    public static final int SORT_ORDER_SIZE = 3;
+
+    public void initAcceptMimes(Intent intent) {
+        if (intent.hasExtra(Intent.EXTRA_MIME_TYPES)) {
+            acceptMimes = intent.getStringArrayExtra(Intent.EXTRA_MIME_TYPES);
+        } else {
+            String glob = intent.getType();
+            acceptMimes = new String[] { glob != null ? glob : "*/*" };
+        }
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(action);
+        out.writeInt(userMode);
+        out.writeStringArray(acceptMimes);
+        out.writeInt(userSortOrder);
+        out.writeInt(allowMultiple ? 1 : 0);
+        out.writeInt(forceSize ? 1 : 0);
+        out.writeInt(showSize ? 1 : 0);
+        out.writeInt(localOnly ? 1 : 0);
+        out.writeInt(forceAdvanced ? 1 : 0);
+        out.writeInt(showAdvanced ? 1 : 0);
+        out.writeInt(stackTouched ? 1 : 0);
+        out.writeInt(restored ? 1 : 0);
+        DurableUtils.writeToParcel(out, stack);
+        out.writeString(currentSearch);
+        out.writeMap(dirState);
+        out.writeList(selectedDocumentsForCopy);
+        out.writeList(excludedAuthorities);
+    }
+
+    public static final Creator<State> CREATOR = new Creator<State>() {
+        @Override
+        public State createFromParcel(Parcel in) {
+            final State state = new State();
+            state.action = in.readInt();
+            state.userMode = in.readInt();
+            state.acceptMimes = in.readStringArray();
+            state.userSortOrder = in.readInt();
+            state.allowMultiple = in.readInt() != 0;
+            state.forceSize = in.readInt() != 0;
+            state.showSize = in.readInt() != 0;
+            state.localOnly = in.readInt() != 0;
+            state.forceAdvanced = in.readInt() != 0;
+            state.showAdvanced = in.readInt() != 0;
+            state.stackTouched = in.readInt() != 0;
+            state.restored = in.readInt() != 0;
+            DurableUtils.readFromParcel(in, state.stack);
+            state.currentSearch = in.readString();
+            in.readMap(state.dirState, null);
+            in.readList(state.selectedDocumentsForCopy, null);
+            in.readList(state.excludedAuthorities, null);
+            return state;
+        }
+
+        @Override
+        public State[] newArray(int size) {
+            return new State[size];
+        }
+    };
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
index 1895a6e..98ffb77 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/DirectoryFragmentModelTest.java
@@ -34,6 +34,9 @@
 import com.android.documentsui.model.DocumentInfo;
 
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 
 
 public class DirectoryFragmentModelTest extends AndroidTestCase {
@@ -77,14 +80,6 @@
         delete(2, 4);
 
         assertEquals(ITEM_COUNT - 2, model.getItemCount());
-
-        // Finalize the deletion.  Provide a callback that just ignores errors.
-        model.finalizeDeletion(
-              new Runnable() {
-                  @Override
-                  public void run() {}
-              });
-        assertEquals(ITEM_COUNT - 2, model.getItemCount());
     }
 
     // Tests that the item count is correct after a deletion is undone.
@@ -95,7 +90,6 @@
         // Undo the deletion
         model.undoDeletion();
         assertEquals(ITEM_COUNT, model.getItemCount());
-
     }
 
     // Tests that the right things are marked for deletion.
@@ -125,6 +119,15 @@
         assertEquals("0", docs.get(0).documentId);
         assertEquals("1", docs.get(1).documentId);
         assertEquals("4", docs.get(2).documentId);
+
+        TestDeletionListener testListener = new TestDeletionListener();
+        model.finalizeDeletion(testListener);
+        testListener.waitForDone();
+
+        docs = getDocumentInfo(0, 1, 2);
+        assertEquals("0", docs.get(0).documentId);
+        assertEquals("1", docs.get(1).documentId);
+        assertEquals("2", docs.get(2).documentId);
     }
 
     // Tests that Model.getItem returns the right items after a deletion is undone.
@@ -176,4 +179,20 @@
             return null;
         }
     }
+
+    private static class TestDeletionListener extends Model.DeletionListener {
+        final CountDownLatch mSignal = new CountDownLatch(1);
+
+        @Override
+        public void onCompletion() {
+            mSignal.countDown();
+        }
+
+        public void waitForDone() {
+            try {
+                boolean timeout = mSignal.await(10, TimeUnit.SECONDS);
+                assertTrue("Timed out waiting for deletion completion", timeout);
+            } catch (InterruptedException e) {}
+        }
+    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
index 25d4ed4..2447469 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManagerTest.java
@@ -20,6 +20,7 @@
 import static org.junit.Assert.assertTrue;
 
 import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
 import android.util.SparseBooleanArray;
 import android.view.MotionEvent;
 import android.view.View;
@@ -27,8 +28,6 @@
 
 import com.android.documentsui.MultiSelectManager.Selection;
 
-import org.junit.Before;
-import org.junit.Test;
 import org.mockito.Mockito;
 
 import java.util.ArrayList;
@@ -36,7 +35,7 @@
 import java.util.List;
 import java.util.Set;
 
-public class MultiSelectManagerTest {
+public class MultiSelectManagerTest extends AndroidTestCase {
 
     private static final List<String> items;
     static {
@@ -54,7 +53,6 @@
     private TestCallback mCallback;
     private EventHelper mEventHelper;
 
-    @Before
     public void setUp() throws Exception {
         mAdapter = new TestAdapter(items);
         mCallback = new TestCallback();
@@ -63,65 +61,61 @@
         mManager.addCallback(mCallback);
     }
 
-    @Test
-    public void mouseClick_StartsSelectionMode() {
+    public void testMouseClick_StartsSelectionMode() {
         click(7);
         assertSelection(7);
     }
 
-    @Test
-    public void mouseClick_ShiftClickExtendsSelection() {
+    public void testMouseClick_NotifiesSelectionChanged() {
+        click(7);
+        mCallback.assertSelectionChanged();
+    }
+
+    public void testMouseClick_ShiftClickExtendsSelection() {
         longPress(7);
         shiftClick(11);
         assertRangeSelection(7, 11);
     }
 
-    @Test
-    public void mouseClick_NoPosition_ClearsSelection() {
+    public void testMouseClick_NoPosition_ClearsSelection() {
         longPress(7);
         click(11);
         click(RecyclerView.NO_POSITION);
         assertSelection();
     }
 
-    @Test
-    public void setSelectionFocusBegin() {
+    public void testSetSelectionFocusBegin() {
         mManager.setItemSelected(7, true);
         mManager.setSelectionFocusBegin(7);
         shiftClick(11);
         assertRangeSelection(7, 11);
     }
 
-    @Test
-    public void longPress_StartsSelectionMode() {
+    public void testLongPress_StartsSelectionMode() {
         longPress(7);
         assertSelection(7);
     }
 
-    @Test
-    public void longPress_SecondPressExtendsSelection() {
+    public void testLongPress_SecondPressExtendsSelection() {
         longPress(7);
         longPress(99);
         assertSelection(7, 99);
     }
 
-    @Test
-    public void singleTapUp_UnselectsSelectedItem() {
+    public void testSingleTapUp_UnselectsSelectedItem() {
         longPress(7);
         tap(7);
         assertSelection();
     }
 
-    @Test
-    public void singleTapUp_NoPosition_ClearsSelection() {
+    public void testSingleTapUp_NoPosition_ClearsSelection() {
         longPress(7);
         tap(11);
         tap(RecyclerView.NO_POSITION);
         assertSelection();
     }
 
-    @Test
-    public void singleTapUp_ExtendsSelection() {
+    public void testSingleTapUp_ExtendsSelection() {
         longPress(99);
         tap(7);
         tap(13);
@@ -129,30 +123,26 @@
         assertSelection(7, 99, 13, 129899);
     }
 
-    @Test
-    public void singleTapUp_ShiftCreatesRangeSelection() {
+    public void testSingleTapUp_ShiftCreatesRangeSelection() {
         longPress(7);
         shiftTap(17);
         assertRangeSelection(7, 17);
     }
 
-    @Test
-    public void singleTapUp_ShiftCreatesRangeSeletion_Backwards() {
+    public void testSingleTapUp_ShiftCreatesRangeSeletion_Backwards() {
         longPress(17);
         shiftTap(7);
         assertRangeSelection(7, 17);
     }
 
-    @Test
-    public void singleTapUp_SecondShiftClickExtendsSelection() {
+    public void testSingleTapUp_SecondShiftClickExtendsSelection() {
         longPress(7);
         shiftTap(11);
         shiftTap(17);
         assertRangeSelection(7, 17);
     }
 
-    @Test
-    public void singleTapUp_MultipleContiguousRangesSelected() {
+    public void testSingleTapUp_MultipleContiguousRangesSelected() {
         longPress(7);
         shiftTap(11);
         tap(20);
@@ -162,16 +152,14 @@
         assertSelectionSize(11);
     }
 
-    @Test
-    public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
+    public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick() {
         longPress(7);
         shiftTap(17);
         shiftTap(10);
         assertRangeSelection(7, 10);
     }
 
-    @Test
-    public void singleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
+    public void testSingleTapUp_ShiftReducesSelectionRange_FromPreviousShiftClick_Backwards() {
         mManager.onLongPress(TestInputEvent.tap(17));
         shiftTap(7);
         shiftTap(14);
@@ -179,16 +167,14 @@
     }
 
 
-    @Test
-    public void singleTapUp_ShiftReversesSelectionDirection() {
+    public void testSingleTapUp_ShiftReversesSelectionDirection() {
         longPress(7);
         shiftTap(17);
         shiftTap(0);
         assertRangeSelection(0, 7);
     }
 
-    @Test
-    public void singleSelectMode() {
+    public void testSingleSelectMode() {
         mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(20);
@@ -196,8 +182,7 @@
         assertSelection(13);
     }
 
-    @Test
-    public void singleSelectMode_ShiftTap() {
+    public void testSingleSelectMode_ShiftTap() {
         mManager = new MultiSelectManager(mAdapter, mEventHelper, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(13);
@@ -205,8 +190,7 @@
         assertSelection(20);
     }
 
-    @Test
-    public void provisionaSelection() {
+    public void testProvisionalSelection() {
         Selection s = mManager.getSelection();
         assertSelection();
 
@@ -298,6 +282,7 @@
         Set<Integer> ignored = new HashSet<>();
         private int mLastChangedPosition;
         private boolean mLastChangedSelected;
+        private boolean mSelectionChanged = false;
 
         @Override
         public void onItemStateChanged(int position, boolean selected) {
@@ -311,7 +296,13 @@
         }
 
         @Override
-        public void onSelectionChanged() {}
+        public void onSelectionChanged() {
+            mSelectionChanged = true;
+        }
+
+        void assertSelectionChanged() {
+            assertTrue(mSelectionChanged);
+        }
     }
 
     private static final class TestHolder extends RecyclerView.ViewHolder {
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
index 87d7e15..aa50b48 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_GridModelTest.java
@@ -22,14 +22,12 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
+import android.test.AndroidTestCase;
 import android.util.SparseBooleanArray;
 
 import com.android.documentsui.MultiSelectManager.GridModel;
 
-import org.junit.After;
-import org.junit.Test;
-
-public class MultiSelectManager_GridModelTest {
+public class MultiSelectManager_GridModelTest extends AndroidTestCase {
 
     private static final int VIEW_PADDING_PX = 5;
     private static final int CHILD_VIEW_EDGE_PX = 100;
@@ -53,14 +51,13 @@
                 });
     }
 
-    @After
+    @Override
     public void tearDown() {
         model = null;
         helper = null;
         lastSelection = null;
     }
 
-    @Test
     public void testSelectionLeftOfItems() {
         setUp(20, 5);
         model.startSelection(new Point(0, 10));
@@ -69,7 +66,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testSelectionRightOfItems() {
         setUp(20, 4);
         model.startSelection(new Point(viewWidth - 1, 10));
@@ -78,7 +74,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testSelectionAboveItems() {
         setUp(20, 4);
         model.startSelection(new Point(10, 0));
@@ -87,7 +82,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testSelectionBelowItems() {
         setUp(5, 4);
         model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
@@ -96,7 +90,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testVerticalSelectionBetweenItems() {
         setUp(20, 4);
         model.startSelection(new Point(106, 0));
@@ -105,7 +98,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testHorizontalSelectionBetweenItems() {
         setUp(20, 4);
         model.startSelection(new Point(0, 105));
@@ -114,7 +106,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testGrowingAndShrinkingSelection() {
         setUp(20, 4);
         model.startSelection(new Point(0, 0));
@@ -145,7 +136,6 @@
         assertEquals(GridModel.NOT_SET, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testSelectionMovingAroundOrigin() {
         setUp(16, 4);
         model.startSelection(new Point(210, 210));
@@ -160,7 +150,6 @@
         assertEquals(10, model.getPositionNearestOrigin());
     }
 
-    @Test
     public void testScrollingBandSelect() {
         setUp(40, 4);
         model.startSelection(new Point(0, 0));
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java
index 51b542b..eddf4ef 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/MultiSelectManager_SelectionTest.java
@@ -18,16 +18,16 @@
 
 import static org.junit.Assert.*;
 
+import android.test.AndroidTestCase;
+
 import com.android.documentsui.MultiSelectManager.Selection;
 
-import org.junit.Before;
-import org.junit.Test;
 
-public class MultiSelectManager_SelectionTest {
+public class MultiSelectManager_SelectionTest extends AndroidTestCase{
 
     private Selection selection;
 
-    @Before
+    @Override
     public void setUp() throws Exception {
         selection = new Selection();
         selection.add(3);
@@ -35,8 +35,7 @@
         selection.add(9);
     }
 
-    @Test
-    public void add() {
+    public void testAdd() {
         // We added in setUp.
         assertEquals(3, selection.size());
         assertContains(3);
@@ -44,29 +43,25 @@
         assertContains(9);
     }
 
-    @Test
-    public void remove() {
+    public void testRemove() {
         selection.remove(3);
         selection.remove(5);
         assertEquals(1, selection.size());
         assertContains(9);
     }
 
-    @Test
-    public void clear() {
+    public void testClear() {
         selection.clear();
         assertEquals(0, selection.size());
     }
 
-    @Test
-    public void isEmpty() {
+    public void testIsEmpty() {
         assertTrue(new Selection().isEmpty());
         selection.clear();
         assertTrue(selection.isEmpty());
     }
 
-    @Test
-    public void sizeAndGet() {
+    public void testSizeAndGet() {
         Selection other = new Selection();
         for (int i = 0; i < selection.size(); i++) {
             other.add(selection.get(i));
@@ -74,13 +69,11 @@
         assertEquals(selection.size(), other.size());
     }
 
-    @Test
-    public void equalsSelf() {
+    public void testEqualsSelf() {
         assertEquals(selection, selection);
     }
 
-    @Test
-    public void equalsOther() {
+    public void testEqualsOther() {
         Selection other = new Selection();
         other.add(3);
         other.add(5);
@@ -89,23 +82,20 @@
         assertEquals(selection.hashCode(), other.hashCode());
     }
 
-    @Test
-    public void equalsCopy() {
+    public void testEqualsCopy() {
         Selection other = new Selection();
         other.copyFrom(selection);
         assertEquals(selection, other);
         assertEquals(selection.hashCode(), other.hashCode());
     }
 
-    @Test
-    public void notEquals() {
+    public void testNotEquals() {
         Selection other = new Selection();
         other.add(789);
         assertFalse(selection.equals(other));
     }
 
-    @Test
-    public void expandBefore() {
+    public void testExpandBefore() {
         selection.expand(2, 10);
         assertEquals(3, selection.size());
         assertContains(13);
@@ -113,8 +103,7 @@
         assertContains(19);
     }
 
-    @Test
-    public void expandAfter() {
+    public void testExpandAfter() {
         selection.expand(10, 10);
         assertEquals(3, selection.size());
         assertContains(3);
@@ -122,8 +111,7 @@
         assertContains(9);
     }
 
-    @Test
-    public void expandSplit() {
+    public void testExpandSplit() {
         selection.expand(5, 10);
         assertEquals(3, selection.size());
         assertContains(3);
@@ -131,8 +119,7 @@
         assertContains(19);
     }
 
-    @Test
-    public void expandEncompased() {
+    public void testExpandEncompased() {
         selection.expand(2, 10);
         assertEquals(3, selection.size());
         assertContains(13);
@@ -140,8 +127,7 @@
         assertContains(19);
     }
 
-    @Test
-    public void collapseBefore() {
+    public void testCollapseBefore() {
         selection.collapse(0, 2);
         assertEquals(3, selection.size());
         assertContains(1);
@@ -149,8 +135,7 @@
         assertContains(7);
     }
 
-    @Test
-    public void collapseAfter() {
+    public void testCollapseAfter() {
         selection.collapse(10, 10);
         assertEquals(3, selection.size());
         assertContains(3);
@@ -158,8 +143,7 @@
         assertContains(9);
     }
 
-    @Test
-    public void collapseAcross() {
+    public void testCollapseAcross() {
         selection.collapse(0, 10);
         assertEquals(0, selection.size());
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
index 1325706..7d3498e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/RootsCacheTest.java
@@ -19,7 +19,6 @@
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
 
-import com.android.documentsui.BaseActivity.State;
 import com.android.documentsui.model.RootInfo;
 
 import com.google.common.collect.Lists;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java b/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
deleted file mode 100644
index be3f251..0000000
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/UnitTests.java
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright (C) 2015 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.documentsui;
-
-import org.junit.runner.RunWith;
-import org.junit.runners.Suite;
-import org.junit.runners.Suite.SuiteClasses;
-
-@RunWith(Suite.class)
-@SuiteClasses({
-        MultiSelectManager_GridModelTest.class,
-        MultiSelectManager_SelectionTest.class,
-        MultiSelectManagerTest.class
-})
-
-/**
- * This test suite can be run using the "art" runtime (which can be built
- * via the `build-art-host` target.) You'll also need to "mma -j32" the
- * DocumentsUI package to ensure all deps are built.
- *
- * <p>Once the dependencies have been built, the tests can be executed as follows:
- *
- * <pre>
- *  CP=$OUT/system/framework/framework.jar:\
- *      $OUT/system/framework/core-junit.jar:\
- *      $OUT/system/app/DocumentsUI/DocumentsUI.apk:\
- *      $OUT/data/app/DocumentsUITests/DocumentsUITests.apk
- *
- *  art -cp $CP org.junit.runner.JUnitCore com.android.documentsui.UnitTests
- * </pre>
- */
-public class UnitTests {}
diff --git a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
index 393771a..18335b6 100644
--- a/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
+++ b/packages/ExternalStorageProvider/src/com/android/externalstorage/ExternalStorageProvider.java
@@ -38,6 +38,7 @@
 import android.provider.DocumentsContract.Document;
 import android.provider.DocumentsContract.Root;
 import android.provider.DocumentsProvider;
+import android.provider.MediaStore;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.DebugUtils;
@@ -380,12 +381,31 @@
     @Override
     public void deleteDocument(String docId) throws FileNotFoundException {
         final File file = getFileForDocId(docId);
-        if (file.isDirectory()) {
+        final boolean isDirectory = file.isDirectory();
+        if (isDirectory) {
             FileUtils.deleteContents(file);
         }
         if (!file.delete()) {
             throw new IllegalStateException("Failed to delete " + file);
         }
+
+        final ContentResolver resolver = getContext().getContentResolver();
+        final Uri externalUri = MediaStore.Files.getContentUri("external");
+
+        // Remove media store entries for any files inside this directory, using
+        // path prefix match. Logic borrowed from MtpDatabase.
+        if (isDirectory) {
+            final String path = file.getAbsolutePath() + "/";
+            resolver.delete(externalUri,
+                    "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
+                    new String[] { path + "%", Integer.toString(path.length()), path });
+        }
+
+        // Remove media store entry for this exact file.
+        final String path = file.getAbsolutePath();
+        resolver.delete(externalUri,
+                "_data LIKE ?1 AND lower(_data)=lower(?2)",
+                new String[] { path, path });
     }
 
     @Override
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
index aeac912..2033159 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardSimPinView.java
@@ -23,6 +23,7 @@
 
 import android.content.Context;
 import android.content.res.ColorStateList;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.app.AlertDialog;
 import android.app.AlertDialog.Builder;
@@ -96,6 +97,12 @@
     }
 
     @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        resetState();
+    }
+
+    @Override
     protected int getPromtReasonStringRes(int reason) {
         // No message on SIM Pin
         return 0;
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
index e342865..57ee319 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -121,7 +121,6 @@
     private static final int MSG_DEVICE_PROVISIONED = 308;
     private static final int MSG_DPM_STATE_CHANGED = 309;
     private static final int MSG_USER_SWITCHING = 310;
-    private static final int MSG_KEYGUARD_VISIBILITY_CHANGED = 311;
     private static final int MSG_KEYGUARD_RESET = 312;
     private static final int MSG_BOOT_COMPLETED = 313;
     private static final int MSG_USER_SWITCH_COMPLETE = 314;
@@ -233,9 +232,6 @@
                 case MSG_USER_SWITCH_COMPLETE:
                     handleUserSwitchComplete(msg.arg1);
                     break;
-                case MSG_KEYGUARD_VISIBILITY_CHANGED:
-                    handleKeyguardVisibilityChanged(msg.arg1);
-                    break;
                 case MSG_KEYGUARD_RESET:
                     handleKeyguardReset();
                     break;
@@ -1344,19 +1340,20 @@
     }
 
     /**
-     * Handle {@link #MSG_KEYGUARD_VISIBILITY_CHANGED}
+     * Notifies that the visibility state of Keyguard has changed.
+     *
+     * <p>Needs to be called from the main thread.
      */
-    private void handleKeyguardVisibilityChanged(int showing) {
-        if (DEBUG) Log.d(TAG, "handleKeyguardVisibilityChanged(" + showing + ")");
-        boolean isShowing = (showing == 1);
-        mKeyguardIsVisible = isShowing;
+    public void onKeyguardVisibilityChanged(boolean showing) {
+        if (DEBUG) Log.d(TAG, "onKeyguardVisibilityChanged(" + showing + ")");
+        mKeyguardIsVisible = showing;
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
-                cb.onKeyguardVisibilityChangedRaw(isShowing);
+                cb.onKeyguardVisibilityChangedRaw(showing);
             }
         }
-        if (!isShowing) {
+        if (!showing) {
             mFingerprintAlreadyAuthenticated = false;
         }
         updateFingerprintListeningState();
@@ -1477,13 +1474,6 @@
         }
     }
 
-    public void sendKeyguardVisibilityChanged(boolean showing) {
-        if (DEBUG) Log.d(TAG, "sendKeyguardVisibilityChanged(" + showing + ")");
-        Message message = mHandler.obtainMessage(MSG_KEYGUARD_VISIBILITY_CHANGED);
-        message.arg1 = showing ? 1 : 0;
-        message.sendToTarget();
-    }
-
     public void sendKeyguardReset() {
         mHandler.obtainMessage(MSG_KEYGUARD_RESET).sendToTarget();
     }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
index 7cc7413..af7f691 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpManager.java
@@ -22,12 +22,14 @@
 import android.hardware.usb.UsbManager;
 import android.mtp.MtpConstants;
 import android.mtp.MtpDevice;
+import android.mtp.MtpEvent;
 import android.mtp.MtpObjectInfo;
+import android.os.CancellationSignal;
 import android.os.ParcelFileDescriptor;
-import android.provider.DocumentsContract.Document;
-import android.provider.DocumentsContract;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.io.FileNotFoundException;
 import java.io.IOException;
 
@@ -188,7 +190,13 @@
         }
     }
 
-    private MtpDevice getDevice(int deviceId) throws IOException {
+    @VisibleForTesting
+    MtpEvent readEvent(int deviceId, CancellationSignal signal) throws IOException {
+        final MtpDevice device = getDevice(deviceId);
+        return device.readEvent(signal);
+    }
+
+    private synchronized MtpDevice getDevice(int deviceId) throws IOException {
         final MtpDevice device = mDevices.get(deviceId);
         if (device == null) {
             throw new IOException("USB device " + deviceId + " is not opened.");
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
index 2c1f115..5547771 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpManagerTest.java
@@ -16,35 +16,101 @@
 
 package com.android.mtp;
 
+import android.app.PendingIntent;
+import android.content.BroadcastReceiver;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.hardware.usb.UsbManager;
+import android.os.CancellationSignal;
+import android.os.OperationCanceledException;
 import android.test.InstrumentationTestCase;
 
+import java.io.IOException;
 import java.util.HashMap;
+import java.util.concurrent.CountDownLatch;
 
+@RealDeviceTest
 public class MtpManagerTest extends InstrumentationTestCase {
-    @RealDeviceTest
-    public void testBasic() throws Exception {
-        final UsbDevice usbDevice = findDevice();
-        final MtpManager manager = new MtpManager(getContext());
-        manager.openDevice(usbDevice.getDeviceId());
-        waitForStorages(manager, usbDevice.getDeviceId());
-        manager.closeDevice(usbDevice.getDeviceId());
+    private static final String ACTION_USB_PERMISSION =
+            "com.android.mtp.USB_PERMISSION";
+    private static final int TIMEOUT_MS = 1000;
+    UsbManager mUsbManager;
+    MtpManager mManager;
+    UsbDevice mUsbDevice;
+    int mRequest;
+
+    @Override
+    public void setUp() throws Exception {
+        mUsbManager = getContext().getSystemService(UsbManager.class);
+        mUsbDevice = findDevice();
+        mManager = new MtpManager(getContext());
+        mManager.openDevice(mUsbDevice.getDeviceId());
+        waitForStorages(mManager, mUsbDevice.getDeviceId());
+    }
+
+    @Override
+    public void tearDown() throws IOException {
+        mManager.closeDevice(mUsbDevice.getDeviceId());
+    }
+
+    public void testCancelEvent() throws Exception {
+        final CancellationSignal signal = new CancellationSignal();
+        final Thread thread = new Thread() {
+            @Override
+            public void run() {
+                try {
+                    mManager.readEvent(mUsbDevice.getDeviceId(), signal);
+                } catch (OperationCanceledException | IOException e) {
+                    show(e.getMessage());
+                }
+            }
+        };
+        thread.start();
+        Thread.sleep(TIMEOUT_MS);
+        signal.cancel();
+        thread.join(TIMEOUT_MS);
+    }
+
+    private void requestPermission(UsbDevice device) throws InterruptedException {
+        if (mUsbManager.hasPermission(device)) {
+            return;
+        }
+        final CountDownLatch latch = new CountDownLatch(1);
+        final BroadcastReceiver receiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                latch.countDown();
+                getInstrumentation().getTargetContext().unregisterReceiver(this);
+            }
+        };
+        getInstrumentation().getTargetContext().registerReceiver(
+                receiver, new IntentFilter(ACTION_USB_PERMISSION));
+        mUsbManager.requestPermission(device, PendingIntent.getBroadcast(
+                getInstrumentation().getTargetContext(),
+                0 /* requstCode */,
+                new Intent(ACTION_USB_PERMISSION),
+                0 /* flags */));
+        latch.await();
+        assertTrue(mUsbManager.hasPermission(device));
     }
 
     private UsbDevice findDevice() throws InterruptedException {
-        final UsbManager usbManager = getContext().getSystemService(UsbManager.class);
         while (true) {
-            final HashMap<String,UsbDevice> devices = usbManager.getDeviceList();
+            final HashMap<String,UsbDevice> devices = mUsbManager.getDeviceList();
             if (devices.size() == 0) {
                 show("Wait for devices.");
                 Thread.sleep(1000);
                 continue;
             }
             final UsbDevice device = devices.values().iterator().next();
-            final UsbDeviceConnection connection = usbManager.openDevice(device);
+            requestPermission(device);
+            final UsbDeviceConnection connection = mUsbManager.openDevice(device);
+            if (connection == null) {
+                fail("Cannot open USB connection.");
+            }
             for (int i = 0; i < device.getInterfaceCount(); i++) {
                 // Since the test runs real environment, we need to call claim interface with
                 // force = true to rob interfaces from other applications.
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
index 9641ad7..22daaf29 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/RealDeviceTest.java
@@ -17,7 +17,10 @@
 package com.android.mtp;
 
 import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
-@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
 @interface RealDeviceTest {}
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
index 9824d28..a243375 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/TestResultInstrumentation.java
@@ -45,8 +45,11 @@
     }
 
     private void show(String tag, Test test, Throwable t) {
+        String message = "";
+        if (t != null && t.getMessage() != null) {
+            message = t.getMessage();
+        }
         TestResultActivity.show(
-                getContext(),
-                String.format("[%s] %s %s", tag, test.toString(), t != null ? t.getMessage() : ""));
+                getContext(), String.format("[%s] %s %s", tag, test.toString(), message));
     }
 }
diff --git a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
index b5d9138..1530a02 100644
--- a/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
+++ b/packages/PrintSpooler/jni/com_android_printspooler_util_BitmapSerializeUtils.cpp
@@ -166,7 +166,7 @@
     }
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     {"nativeReadBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) readBitmapPixels},
     {"nativeWriteBitmapPixels", "(Landroid/graphics/Bitmap;I)V", (void *) writeBitmapPixels},
 };
diff --git a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
index 8e41a34..f88eca5 100644
--- a/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
+++ b/packages/PrintSpooler/res/values-uz-rUZ/strings.xml
@@ -46,7 +46,7 @@
     <string name="savetopdf_button" msgid="2976186791686924743">"PDF sifatida saqlash"</string>
     <string name="print_options_expanded" msgid="6944679157471691859">"Chop qilish tanlamalari yoyildi"</string>
     <string name="print_options_collapsed" msgid="7455930445670414332">"Chop qilish tanlamalari yig‘ildi"</string>
-    <string name="search" msgid="5421724265322228497">"Izlash"</string>
+    <string name="search" msgid="5421724265322228497">"Qidirish"</string>
     <string name="all_printers_label" msgid="3178848870161526399">"Barcha printerlar"</string>
     <string name="add_print_service_label" msgid="5356702546188981940">"Xizmat qo‘shish"</string>
     <string name="print_search_box_shown_utterance" msgid="7967404953901376090">"Izlash oynasi ko‘rsatildi"</string>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1cd2908..c324abd 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -204,9 +204,6 @@
     <!-- Default for Settings.Secure.WAKE_GESTURE_ENABLED -->
     <bool name="def_wake_gesture_enabled">true</bool>
 
-    <!-- Default for Settings.Global.GUEST_USER_ENABLED -->
-    <bool name="def_guest_user_enabled">true</bool>
-
     <!-- Default state of tap to wake -->
     <bool name="def_double_tap_to_wake">true</bool>
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
index ee296d9..d4e428e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DatabaseHelper.java
@@ -1693,20 +1693,7 @@
         }
 
         if (upgradeVersion < 105) {
-            if (mUserHandle == UserHandle.USER_SYSTEM) {
-                db.beginTransaction();
-                SQLiteStatement stmt = null;
-                try {
-                    stmt = db.compileStatement("INSERT OR IGNORE INTO global(name,value)"
-                            + " VALUES(?,?);");
-                    loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
-                            R.bool.def_guest_user_enabled);
-                    db.setTransactionSuccessful();
-                } finally {
-                    db.endTransaction();
-                    if (stmt != null) stmt.close();
-                }
-            }
+            // No-op: GUEST_USER_ENABLED setting was removed
             upgradeVersion = 105;
         }
 
@@ -2705,8 +2692,6 @@
 
             loadSetting(stmt, Settings.Global.DEVICE_NAME, getDefaultDeviceName());
 
-            loadBooleanSetting(stmt, Settings.Global.GUEST_USER_ENABLED,
-                    R.bool.def_guest_user_enabled);
             loadSetting(stmt, Settings.Global.ENHANCED_4G_MODE_ENABLED,
                     ImsConfig.FeatureValueConstants.ON);
 
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 93dc889..8fc7ad0 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -206,7 +206,7 @@
                   android:resumeWhilePausing="true"
                   android:screenOrientation="behind"
                   android:resizeableActivity="true"
-                  android:theme="@style/config_recents_activity_theme">
+                  android:theme="@style/RecentsTheme.Wallpaper">
             <intent-filter>
                 <action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
             </intent-filter>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock.xml b/packages/SystemUI/res/drawable/ic_qs_lock.xml
new file mode 100644
index 0000000..204af7e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_lock.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="@color/keyguard_affordance"
+        android:pathData="M18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM12.0,17.0c-1.1,0.0 -2.0,-0.9 -2.0,-2.0s0.9,-2.0 2.0,-2.0c1.1,0.0 2.0,0.9 2.0,2.0S13.1,17.0 12.0,17.0zM15.1,8.0L8.9,8.0L8.9,6.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1L15.1,8.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_qs_lock_open.xml b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
new file mode 100644
index 0000000..c877f06
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_qs_lock_open.xml
@@ -0,0 +1,25 @@
+<!--
+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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+
+    <path
+        android:fillColor="@color/keyguard_affordance"
+        android:pathData="M12.0,17.0c1.1,0.0 2.0,-0.9 2.0,-2.0s-0.9,-2.0 -2.0,-2.0c-1.1,0.0 -2.0,0.9 -2.0,2.0S10.9,17.0 12.0,17.0zM18.0,8.0l-1.0,0.0L17.0,6.0c0.0,-2.8 -2.2,-5.0 -5.0,-5.0C9.2,1.0 7.0,3.2 7.0,6.0l1.9,0.0c0.0,-1.7 1.4,-3.1 3.1,-3.1c1.7,0.0 3.1,1.4 3.1,3.1l0.0,2.0L6.0,8.0c-1.1,0.0 -2.0,0.9 -2.0,2.0l0.0,10.0c0.0,1.1 0.9,2.0 2.0,2.0l12.0,0.0c1.1,0.0 2.0,-0.9 2.0,-2.0L20.0,10.0C20.0,8.9 19.1,8.0 18.0,8.0zM18.0,20.0L6.0,20.0L6.0,10.0l12.0,0.0L18.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
new file mode 100644
index 0000000..f11b690
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_bottom.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF0000FF"
+        android:pathData="M0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0zM4.0,10.0l16.0,0.0l0.0,10.0L4.0,20.0L4.0,10.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml
new file mode 100644
index 0000000..79ade42
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_left.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF0000FF"
+        android:pathData="M24.0,0.0L0.0,0.0l0.0,24.0l24.0,0.0L24.0,0.0zM14.0,4.0l0.0,16.0L4.0,20.0L4.0,4.0L14.0,4.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml
new file mode 100644
index 0000000..49c2a38
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_right.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF0000FF"
+        android:pathData="M0.0,24.0l24.0,0.0L24.0,0.0L0.0,0.0L0.0,24.0zM10.0,20.0L10.0,4.0l10.0,0.0l0.0,16.0L10.0,20.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml
new file mode 100644
index 0000000..c3abec2
--- /dev/null
+++ b/packages/SystemUI/res/drawable/vector_drawable_place_dock_top.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF0000FF"
+        android:pathData="M24.0,24.0L24.0,0.0L0.0,0.0l0.0,24.0L24.0,24.0zM20.0,14.0L4.0,14.0L4.0,4.0l16.0,0.0L20.0,14.0z"/>
+</vector>
diff --git a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
index a718d4d..0a4c086 100644
--- a/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-land/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal">
         <Button
+            android:id="@+id/place_dock_left"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_left" />
+        <Button
+            android:id="@+id/place_dock_right"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_right" />
+        <Button
             android:id="@+id/place_left"
             android:layout_width="36dp"
             android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
index 250f53d..bf5207a 100644
--- a/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-port/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal">
         <Button
+            android:id="@+id/place_dock_top"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_top" />
+        <Button
+            android:id="@+id/place_dock_bottom"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_bottom" />
+        <Button
             android:id="@+id/place_top"
             android:layout_width="36dp"
             android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
index 26c9b1a..6e92afc 100644
--- a/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp-land/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal">
         <Button
+            android:id="@+id/place_dock_left"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_left" />
+        <Button
+            android:id="@+id/place_dock_right"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_right" />
+        <Button
             android:id="@+id/place_left"
             android:layout_width="36dp"
             android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
index e180daa..faa5f4b 100644
--- a/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
+++ b/packages/SystemUI/res/layout-sw600dp-port/recents_task_resize_dialog.xml
@@ -27,6 +27,20 @@
         android:layout_height="wrap_content"
         android:orientation="horizontal">
         <Button
+            android:id="@+id/place_dock_top"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_top" />
+        <Button
+            android:id="@+id/place_dock_bottom"
+            android:layout_width="36dp"
+            android:layout_height="36dp"
+            android:layout_weight="1"
+            android:layout_margin="10dp"
+            android:background="@drawable/vector_drawable_place_dock_bottom" />
+        <Button
             android:id="@+id/place_top"
             android:layout_width="36dp"
             android:layout_height="36dp"
diff --git a/packages/SystemUI/res/layout/recents.xml b/packages/SystemUI/res/layout/recents.xml
index 8140dd6..064d225 100644
--- a/packages/SystemUI/res/layout/recents.xml
+++ b/packages/SystemUI/res/layout/recents.xml
@@ -39,12 +39,6 @@
            android:layout_width="match_parent"
            android:layout_height="match_parent" />
 
-    <!-- Debug Overlay View -->
-    <ViewStub android:id="@+id/debug_overlay_stub"
-           android:layout="@layout/recents_debug_overlay"
-           android:layout_width="match_parent"
-           android:layout_height="match_parent" />
-
     <!-- Nav Bar Scrim View -->
     <ImageView
         android:id="@+id/nav_bar_scrim"
diff --git a/packages/SystemUI/res/layout/recents_debug_overlay.xml b/packages/SystemUI/res/layout/recents_debug_overlay.xml
deleted file mode 100644
index d23495e..0000000
--- a/packages/SystemUI/res/layout/recents_debug_overlay.xml
+++ /dev/null
@@ -1,35 +0,0 @@
-<?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.
--->
-<com.android.systemui.recents.views.DebugOverlayView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="match_parent" 
-    android:layout_height="match_parent"
-    android:focusable="false">
-    <SeekBar
-        android:id="@+id/debug_seek_bar_1"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:layout_marginTop="25dp" />
-    <SeekBar
-        android:id="@+id/debug_seek_bar_2"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_gravity="top"
-        android:layout_marginTop="50dp" />
-</com.android.systemui.recents.views.DebugOverlayView>
-
-
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index 1473f24..c7c7f1a 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Net\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Net\nwekkers"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laai tans (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laai tans vinnig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laai tans stadig (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tot vol)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Wissel gebruiker"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Wissel gebruiker, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index 7ab6af9..f49f5bc 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ቅድሚያ ተሰጪ\nብቻ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ማንቂያዎች\nብቻ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ሃይል በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ኃይል በፍጥነት በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ኃይል በዝግታ በመሙላት ላይ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> እስከሚሞላ ድረስ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ተጠቃሚ ቀይር"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ተጠቃሚ ይለውጡ፣ የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"የአሁን ተጠቃሚ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index bd02650..aaf20cc 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -329,6 +329,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"الأولوية \nفقط"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"التنبيهات\nفقط"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"جارٍ الشحن (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الامتلاء)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"جارٍ الشحن سريعًا (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"جارٍ الشحن ببطء (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> حتى الاكتمال)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تبديل المستخدم"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تبديل المستخدم، المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"المستخدم الحالي <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index a0d7d2b..0efc82b 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnız\nprioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnız\nalarmlar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sürətli qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ləng qidalanır (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> dolana kimi)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"İstifadəçiləri dəyişin, indiki istifadəçi: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Cari istifadəçi <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index a14d0fc..6805779 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nс приоритет"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nбудилници"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарежда се (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Зарежда се бързо (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Зарежда се бавно (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до пълно зареждане)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Превключване между потребителите"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Превключване на потребителя – текущият е <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Текущ потребител – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index e819d54..c0ffe2c 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"শুধুমাত্র\nঅগ্রাধিকার"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"শুধুমাত্র\nঅ্যালার্মগুলি"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"দ্রুত চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ধীরে ধীরে চার্জ হচ্ছে (পূর্ণ হতে <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> সময় বাকি)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ব্যবহারকারী পাল্টে দিন"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ব্যবহারকারী পাল্টান, বর্তমান ব্যবহারকারী <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> হল বর্তমান ব্যবহারকারী"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index cc37162..c955f34 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Només\ninterr. prior."</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Només\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregant (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar la càrrega)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Càrrega ràpida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Càrrega lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> per completar-se)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Canvia d\'usuari"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Canvia l\'usuari. Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuari actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -406,7 +408,7 @@
     <string name="volumeui_notification_title" msgid="4906770126345910955">"<xliff:g id="APP_NAME">%1$s</xliff:g> és el diàleg de volum"</string>
     <string name="volumeui_notification_text" msgid="1826889705095768656">"Toca per restaurar l\'original."</string>
     <string name="managed_profile_foreground_toast" msgid="5421487114739245972">"Estàs utilitzant el perfil professional"</string>
-    <string name="system_ui_tuner" msgid="708224127392452018">"Configurador de la IU del sistema"</string>
+    <string name="system_ui_tuner" msgid="708224127392452018">"Personalitzador d\'interfície d\'usuari"</string>
     <string name="show_battery_percentage" msgid="5444136600512968798">"Mostra el percentatge de la bateria inserit"</string>
     <string name="show_battery_percentage_summary" msgid="3215025775576786037">"Mostra el percentatge del nivell de bateria dins de la icona de la barra d\'estat quan no s\'estigui carregant"</string>
     <string name="quick_settings" msgid="10042998191725428">"Configuració ràpida"</string>
@@ -428,12 +430,12 @@
     <string name="accessibility_status_bar_hotspot" msgid="4099381329956402865">"Zona Wi-Fi"</string>
     <string name="accessibility_managed_profile" msgid="6613641363112584120">"Perfil professional"</string>
     <string name="tuner_warning_title" msgid="7094689930793031682">"Diversió per a uns quants, però no per a tothom"</string>
-    <string name="tuner_warning" msgid="8730648121973575701">"El Configurador de la IU del sistema presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
+    <string name="tuner_warning" msgid="8730648121973575701">"El Personalitzador d\'interfície d\'usuari presenta opcions addicionals per canviar i personalitzar la interfície d\'usuari d\'Android. És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
     <string name="tuner_persistent_warning" msgid="8597333795565621795">"És possible que aquestes funcions experimentals canviïn, deixin de funcionar o desapareguin en versions futures. Continua amb precaució."</string>
     <string name="got_it" msgid="2239653834387972602">"D\'acord"</string>
-    <string name="tuner_toast" msgid="603429811084428439">"Enhorabona! El Configurador de la IU del sistema s\'ha afegit a Configuració."</string>
+    <string name="tuner_toast" msgid="603429811084428439">"Enhorabona! El Personalitzador d\'interfície d\'usuari s\'ha afegit a Configuració."</string>
     <string name="remove_from_settings" msgid="8389591916603406378">"Treu de Configuració"</string>
-    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols treure el Configurador de la UI del sistema de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string>
+    <string name="remove_from_settings_prompt" msgid="6069085993355887748">"Vols suprimir el Personalitzador d\'interfície d\'usuari de Configuració i deixar d\'utilitzar-ne totes les funcions?"</string>
     <string name="activity_not_found" msgid="348423244327799974">"L\'aplicació no està instal·lada al dispositiu"</string>
     <string name="clock_seconds" msgid="7689554147579179507">"Mostra els segons del rellotge"</string>
     <string name="clock_seconds_desc" msgid="6282693067130470675">"Mostra els segons del rellotge a la barra d\'estat. Això pot afectar la durada de la bateria."</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index a73947f..18fd994 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -329,6 +329,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Pouze\nprioritní"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Pouze\nbudíky"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Rychlé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Pomalé nabíjení (plně nabito za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Přepnout uživatele"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Přepnout uživatele, aktuální uživatel: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuální uživatel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 6f49187..5a2dd33 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -183,12 +183,12 @@
     <string name="accessibility_quick_settings_airplane_on" msgid="6406141469157599296">"Flytilstand er slået til."</string>
     <string name="accessibility_quick_settings_airplane_changed_off" msgid="66846307818850664">"Flytilstand er slået fra."</string>
     <string name="accessibility_quick_settings_airplane_changed_on" msgid="8983005603505087728">"Flytilstand er slået til."</string>
-    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Vil ikke forstyrres\" er slået til, kun prioritet."</string>
-    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"Vil ikke forstyrres\" er slået til, total stilhed."</string>
-    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Vil ikke forstyrres\" er slået til, kun alarmer."</string>
-    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Vil ikke forstyrres\" er slået fra."</string>
-    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Vil ikke forstyrres\" er slået fra."</string>
-    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Vil ikke forstyrres\" er slået til."</string>
+    <string name="accessibility_quick_settings_dnd_priority_on" msgid="1448402297221249355">"\"Forstyr ikke\" er slået til, kun prioritet."</string>
+    <string name="accessibility_quick_settings_dnd_none_on" msgid="6882582132662613537">"\"Forstyr ikke\" er slået til, total stilhed."</string>
+    <string name="accessibility_quick_settings_dnd_alarms_on" msgid="9152834845587554157">"\"Forstyr ikke\" er slået til, kun alarmer."</string>
+    <string name="accessibility_quick_settings_dnd_off" msgid="2371832603753738581">"\"Forstyr ikke\" er slået fra."</string>
+    <string name="accessibility_quick_settings_dnd_changed_off" msgid="898107593453022935">"\"Forstyr ikke\" er slået fra."</string>
+    <string name="accessibility_quick_settings_dnd_changed_on" msgid="4483780856613561039">"\"Forstyr ikke\" er slået til."</string>
     <string name="accessibility_quick_settings_bluetooth_off" msgid="2133631372372064339">"Bluetooth er slået fra."</string>
     <string name="accessibility_quick_settings_bluetooth_on" msgid="7681999166216621838">"Bluetooth er slået til."</string>
     <string name="accessibility_quick_settings_bluetooth_connecting" msgid="6953242966685343855">"Opretter forbindelse til Bluetooth."</string>
@@ -236,7 +236,7 @@
     <string name="dessert_case" msgid="1295161776223959221">"Dessertcase"</string>
     <string name="start_dreams" msgid="7219575858348719790">"Dagdrøm"</string>
     <string name="ethernet_label" msgid="7967563676324087464">"Ethernet"</string>
-    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Vil ikke forstyrres"</string>
+    <string name="quick_settings_dnd_label" msgid="8735855737575028208">"Forstyr ikke"</string>
     <string name="quick_settings_dnd_priority_label" msgid="483232950670692036">"Kun prioritet"</string>
     <string name="quick_settings_dnd_alarms_label" msgid="2559229444312445858">"Kun Alarmer"</string>
     <string name="quick_settings_dnd_none_label" msgid="5025477807123029478">"Total stilhed"</string>
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kun\nprioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kun\nalarmer"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Oplader (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hurtig opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langsom opladning (fuldt opladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skift bruger"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skift bruger. Nuværende bruger er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Nuværende bruger: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index a659077..a8143a4 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Nur\nwichtige"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Nur\nWecker"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Wird aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Wird schnell aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wird langsam aufgeladen (voll in <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Nutzer wechseln"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Nutzer wechseln. Aktueller Nutzer: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktueller Nutzer <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index bcfc458..6031d3b 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Μόνο\nπροτεραιότητας"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Μόνο\nειδοποιήσεις"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Γρήγορη φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Αργή φόρτιση (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> για πλήρη φόρτιση)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Εναλλαγή χρήστη"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Εναλλαγή χρήστη, τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Τρέχων χρήστης <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fb781d4..bef7661 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index fb781d4..bef7661 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index fb781d4..bef7661 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priority\nonly"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarms\nonly"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charging (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charging rapidly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charging slowly (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> until full)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Switch user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Switch user, current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Current user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-en/donottranslate.xml b/packages/SystemUI/res/values-en/donottranslate.xml
new file mode 100644
index 0000000..9f04e1f
--- /dev/null
+++ b/packages/SystemUI/res/values-en/donottranslate.xml
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 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>
+    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+    <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time_fast</item>
+    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+    <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time_slowly</item>
+</resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 10834a2..1590265 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\nprioridad"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (faltan <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carga rápida (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carga lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar la carga)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"El usuario actual es <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 37c81f4..082e762 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo\ncon prioridad"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nalarmas"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para completar)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hasta completar)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar de usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar de usuario (usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index f4218a3..4add147 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Ainult\nprioriteetsed"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ainult\nalarmid"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Kiirlaadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Aeglane laadimine (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>, kuni seade on täis)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kasutaja vahetamine"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kasutaja vahetamine, praegune kasutaja: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Praegune kasutaja <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index 0e5532c..4f5c9f2 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Lehentasunezkoak\nsoilik"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmak\nsoilik"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Bizkor kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mantso kargatzen (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> guztiz kargatu arte)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Aldatu erabiltzailea"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Aldatu erabiltzailez. <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> da saioa hasita duena."</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Uneko erabiltzailea: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index 7593f46..6fa7e1c 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -275,7 +275,7 @@
     <string name="quick_settings_inversion_label" msgid="8790919884718619648">"برگردان رنگ‌ها"</string>
     <string name="quick_settings_color_space_label" msgid="853443689745584770">"حالت تصحیح رنگ"</string>
     <string name="quick_settings_more_settings" msgid="326112621462813682">"تنظیمات بیشتر"</string>
-    <string name="quick_settings_done" msgid="3402999958839153376">"انجام شد"</string>
+    <string name="quick_settings_done" msgid="3402999958839153376">"تمام"</string>
     <string name="quick_settings_connected" msgid="1722253542984847487">"متصل"</string>
     <string name="quick_settings_connecting" msgid="47623027419264404">"در حال اتصال..."</string>
     <string name="quick_settings_tethering_label" msgid="7153452060448575549">"اتصال به اینترنت با تلفن همراه"</string>
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"فقط\nاولویت‌دار"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"فقط\nهشدارها"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"در حال شارژ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"در حال شارژ سریع (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"در حال شارژ آهسته (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> تا شارژ کامل)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"تغییر کاربر"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"تعویض کاربر، کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"کاربر کنونی <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index 6c4a029..655cf31 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vain\ntärkeät"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vain\nherätykset"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ladataan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kunnes täynnä)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nopea lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Hidas lataus (latausaikaa jäljellä <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Vaihda käyttäjää"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Vaihda käyttäjä (nyt <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Nykyinen käyttäjä: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 07a2fc3..2f2c331 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorités\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours... (chargée à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente en cours... (chargé dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 0aa45ae..9f34431 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priorité\nuniquement"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alarmes\nuniquement"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Charge en cours… (chargé à 100 %% dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Charge rapide… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Charge lente… (chargé à 100 % dans <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Changer d\'utilisateur"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Changer d\'utilisateur (utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilisateur actuel : <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index ec64f22..df90ef4 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Só\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Só\nalarmas"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Cargando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para finalizar a carga)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Cargando rápido (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Cargando lento (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para rematar a carga)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambiar usuario"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambiar usuario, usuario actual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuario actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index e873c95..42ee460 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ફક્ત\nપ્રાધાન્યતા"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ફક્ત\nએલાર્મ્સ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ચાર્જ થઈ રહ્યું છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ઝડપથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ધીમેથી ચાર્જિંગ થઇ રહી છે (પૂર્ણ થવામાં <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> બાકી)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"વપરાશકર્તા સ્વિચ કરો"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"વપરાશકર્તાને સ્વિચ કરો, વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"વર્તમાન વપરાશકર્તા <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 83ac46e..86f536d 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवल\nप्राथमिकता"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवल\nअलार्म"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हो रहा है (पूरा होने में <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> बाकी)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"तेज़ी से चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में हो जाएगा)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"धीरे चार्ज हो रहा है (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> में पूरा हो जाएगा)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"उपयोगकर्ता स्विच करें"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"उपयोगकर्ता स्विच करें, वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"वर्तमान उपयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index b5d9931..043e7ad 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -326,6 +326,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprioritetno"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Brzo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sporo punjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napunjenosti)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Promjena korisnika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Promjena korisnika, trenutačni korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutačan korisnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 79390a6..e2b0812 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Csak\nprioritás"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Csak\nriasztások"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Gyors töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lassú töltés (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> a teljes töltöttségig)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Felhasználóváltás"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Felhasználóváltás (a jelenlegi felhasználó: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Jelenlegi felhasználó (<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 9f48b26..f8fc232 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Միայն\nկարևորները"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Միայն\nզարթուցիչ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> մինչև լրիվ լիցքավորումը)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Արագ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Դանդաղ լիցքավորում (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>՝ մինչև լցվելը)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Անջատել օգտվողին"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Փոխել օգտվողին. ներկայիս օգտվողն է՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ընթացիկ օգտվողը՝ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 60024115..7dbcda9 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Hanya\nprioritas"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Hanya\nalarm"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengisi daya (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengisi daya dengan cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengisi daya dengan lambat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hingga penuh)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Beralih pengguna"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ganti pengguna, pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pengguna saat ini <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index e8e0530..b28b6fd 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Aðeins\nforgangur"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Aðeins\nvekjarar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Í hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Í hraðri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Í hægri hleðslu (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> fram að fullri hleðslu)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Skipta um notanda"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Skipta um notanda; núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Núverandi notandi er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 8ee5f07..54e6f56 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Solo con\npriorità"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Solo\nsveglie"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"In carica (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ricarica veloce (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Ricarica lenta (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> al termine)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Cambio utente"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Cambia utente, utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utente corrente <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
@@ -354,7 +356,7 @@
     <string name="user_remove_user_title" msgid="4681256956076895559">"Rimuovere l\'utente?"</string>
     <string name="user_remove_user_message" msgid="1453218013959498039">"Tutte le app e i dati di questo utente verranno eliminati."</string>
     <string name="user_remove_user_remove" msgid="7479275741742178297">"Rimuovi"</string>
-    <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio batteria attivo"</string>
+    <string name="battery_saver_notification_title" msgid="237918726750955859">"Risparmio energetico attivo"</string>
     <string name="battery_saver_notification_text" msgid="820318788126672692">"Riduce le prestazioni e i dati in background"</string>
     <string name="battery_saver_notification_action_text" msgid="109158658238110382">"Disattiva risparmio energetico"</string>
     <string name="notification_hidden_text" msgid="1135169301897151909">"Contenuti nascosti"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 44058a3..c959feb 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"התראות בעדיפות\nבלבד"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"התראות\nבלבד"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"טוען (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד לסיום)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"בטעינה מהירה (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"בטעינה איטית (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> עד למילוי)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"החלפת משתמש"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"החלף משתמש. המשתמש הנוכחי הוא <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"משתמש נוכחי <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index a73f4c1..29476d8 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -327,10 +327,12 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"重要な\n通知のみ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"アラーム\nのみ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中(フル充電まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"急速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"低速充電中(完了まで<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ユーザーを切り替える"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ユーザーを切り替える、現在のユーザーは<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"現在のユーザー: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
-    <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"プロフィールを表示"</string>
+    <string name="accessibility_multi_user_switch_quick_contact" msgid="3020367729287990475">"プロファイルを表示"</string>
     <string name="user_add_user" msgid="5110251524486079492">"ユーザーを追加"</string>
     <string name="user_new_user_name" msgid="426540612051178753">"新しいユーザー"</string>
     <string name="guest_nickname" msgid="8059989128963789678">"ゲスト"</string>
@@ -364,10 +366,10 @@
     <string name="media_projection_action_text" msgid="8470872969457985954">"今すぐ開始"</string>
     <string name="empty_shade_text" msgid="708135716272867002">"通知はありません"</string>
     <string name="device_owned_footer" msgid="3802752663326030053">"端末が監視されている可能性があります"</string>
-    <string name="profile_owned_footer" msgid="8021888108553696069">"プロフィールが監視されている可能性があります"</string>
+    <string name="profile_owned_footer" msgid="8021888108553696069">"プロファイルが監視されている可能性があります"</string>
     <string name="vpn_footer" msgid="2388611096129106812">"ネットワークが監視されている可能性があります"</string>
     <string name="monitoring_title_device_owned" msgid="7121079311903859610">"端末の監視"</string>
-    <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロフィールの監視"</string>
+    <string name="monitoring_title_profile_owned" msgid="6790109874733501487">"プロファイルの監視"</string>
     <string name="monitoring_title" msgid="169206259253048106">"ネットワーク監視"</string>
     <string name="disable_vpn" msgid="4435534311510272506">"VPNを無効にする"</string>
     <string name="disconnect_vpn" msgid="1324915059568548655">"VPNを切断"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index f1035a8..d83c9e9 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"მხოლოდ\nპრიორიტეტულები"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"მხოლოდ\nგაფრთხილებები"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>-ის შეცვლა დასრულებამდე)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"იტენება სწრაფად (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"იტენება ნელა (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> სრულ დატენვამდე)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"მომხმარებლის გადართვა"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"მომხმარებლის გდართვა. ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ამჟამინდელი მომხმარებელი <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 8b82e5f..5c066b3 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Тек\nбасымдық"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Тек\nдабылдар"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Жылдам зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Баяу зарядталуда (толғанша <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Пайдаланушыны ауыстыру"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Пайдаланушыны ауыстыру, ағымдағы пайдаланушы <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Ағымдағы пайдаланушы: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index b8db00f..4c469b0 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"អាទិភាព\nប៉ុណ្ណោះ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"សំឡេងរោទ៍\nប៉ុណ្ណោះ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"កំពុង​បញ្ចូល​ថ្ម (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើប​ពេញ)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ថ្មកំពុងសាកលឿន (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ថ្មកំពុងសាកយឺតៗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ទើបពេញ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ប្ដូរ​អ្នក​ប្រើ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ប្ដូរ​អ្នកប្រើ ​អ្នកប្រើ​បច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"អ្នកប្រើបច្ចុប្បន្ន <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 316c04f..4215a91 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ಆದ್ಯತೆ\nಮಾತ್ರ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ಅಲಾರಮ್‌ಗಳು\nಮಾತ್ರ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ ( ಪೂರ್ತಿ ಆಗುವವರೆಗೆ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ವೇಗವಾಗಿ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ನಿಧಾನ ಚಾರ್ಜ್ ಆಗುತ್ತಿದೆ (ಪೂರ್ಣಗೊಳ್ಳಲು <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ಬಳಕೆದಾರರನ್ನು ಬದಲಿಸಿ, ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"<xliff:g id="CURRENT_USER_NAME">%s</xliff:g> ಪ್ರಸ್ತುತ ಬಳಕೆದಾರ"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index d7f1543..8ee5946 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"중요 알림만\n허용"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"알람만\n"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"고속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"저속 충전 중(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> 후 충전 완료)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"사용자 전환"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"사용자 전환, 현재 사용자 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"현재 사용자: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index 65f91a2..ce0afd4 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Артыкчылыктуу\nгана"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ойготкучтар\nгана"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Кубатталууда (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> толгонго чейин)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Тез кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Жай кубатталууда (толгонго чейин <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> калды)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Колдонуучуну которуу"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Колдонуучуну күйгүзүү, учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Учурдагы колдонуучу <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-land/config.xml b/packages/SystemUI/res/values-land/config.xml
index d608e25..f7e2344 100644
--- a/packages/SystemUI/res/values-land/config.xml
+++ b/packages/SystemUI/res/values-land/config.xml
@@ -20,10 +20,6 @@
 <!-- These resources are around just to allow their values to be customized
      for different hardware and product builds. -->
 <resources>
-    <!-- Whether we're using the tablet-optimized recents interface (we use this
-     value at runtime for some things) -->
-    <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
-
     <!-- The maximum number of rows in the QuickSettings -->
     <integer name="quick_settings_max_rows">2</integer>
 
diff --git a/packages/SystemUI/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index a9e7735..6ef1ada 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -19,28 +19,6 @@
     <!-- thickness (width) of the navigation bar on phones that require it -->
     <dimen name="navigation_bar_size">@*android:dimen/navigation_bar_width</dimen>
 
-    <!-- Recent Applications parameters -->
-    <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">0dp</dimen>
-    <!-- How far the thumbnail for a recent app appears from top edge -->
-    <dimen name="status_bar_recents_thumbnail_top_margin">28dp</dimen>
-    <!-- Padding for text descriptions -->
-    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
-    <!-- Width of application label text -->
-    <dimen name="status_bar_recents_app_label_width">156dip</dimen>
-    <!-- Left margin of application label text -->
-    <dimen name="status_bar_recents_app_label_left_margin">12dip</dimen>
-    <!-- Margin between recents container and glow on the right -->
-    <dimen name="status_bar_recents_right_glow_margin">0dip</dimen>
-    <!-- Padding between recents items -->
-    <dimen name="status_bar_recents_item_padding">2dip</dimen>
-    <!-- Where to place the app icon over the thumbnail -->
-    <dimen name="status_bar_recents_app_icon_left_margin">8dp</dimen>
-    <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
-
-    <!-- The side padding for the task stack as a percentage of the width. -->
-    <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.26</item>
-
     <!-- Standard notification width + gravity -->
     <dimen name="notification_panel_width">@dimen/standard_notification_panel_width</dimen>
     <integer name="notification_panel_layout_gravity">@integer/standard_notification_panel_layout_gravity</integer>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 50b4522..b45395e 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ບຸ​ລິ​ມະ​ສິດ\nເທົ່າ​ນັ້ນ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ໂມງ​ປຸກ\nເທົ່າ​ນັ້ນ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ກຳ​ລັງ​ສາກ​ໄຟ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ກວ່າ​ຈ​ະ​ເຕັມ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ສະ​ລັບ​ຜູ່ໃຊ້"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ປ່ຽນຜູ່ໃຊ້, ຜູ່ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ຜູ້ໃຊ້ປະຈຸບັນ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 9082778..194668b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tik\nprioritetiniai"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tik\nsignalai"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Greitai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lėtai kraunama (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> iki visiško įkrovimo)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Perjungti naudotoją"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Perjungti naudotoją, dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Dabartinis naudotojas <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 5fb4bb0..2b3be58 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -326,6 +326,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tikai\nprioritārie"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tikai\nsignāli"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Notiek uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Ātra uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lēna uzlāde (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> līdz pilnīgai uzlādei)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mainīt lietotāju"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Pārslēgt lietotāju; pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pašreizējais lietotājs: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 8571b3f..912c30f 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприоритетни"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Се полни (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Бавно полнење (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> додека не се наполни)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Промени го корисникот"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промени го корисникот, тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Тековен корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 4b11962..c85ecc7 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"മുൻഗണന\nമാത്രം"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"അലാറങ്ങൾ\nമാത്രം"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ചാർജ്ജുചെയ്യുന്നു (പൂർണ്ണമാകുന്നതിന്, <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"വേഗത്തിൽ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"പതുക്കെ ചാർജുചെയ്യുന്നു (പൂർണ്ണമാകാൻ <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ഉപയോക്താവ് മാറുക"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ഉപയോക്താവിനെ മാറ്റുക, <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> എന്നയാളാണ് നിലവിലുള്ള ഉപയോക്താവ്"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index d1dbd6d..6b29aff 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -323,6 +323,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Зөвхөн\nхамгийн чухлыг"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Зөвхөн\nсэрүүлэг"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Цэнэглэж байна (дүүргэхэд <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> шаардлагатай)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Хэрэглэгчийг сэлгэх"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Хэрэглэгчийг сэлгэх, одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Одоогийн хэрэглэгч <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 2b9d953..9d518a0 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"केवळ\nप्राधान्य"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"केवळ\nअलार्म"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) चार्ज होत आहे"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) वेगाने चार्ज होत आहे"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण होईपर्यंत) हळूहळू चार्ज होत आहे"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"वापरकर्ता स्विच करा"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"वापरकर्ता स्विच करा, वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"वर्तमान वापरकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 01f7edf..10dca3e 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Keutamaan\nsahaja"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Penggera\nsahaja"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Mengecas (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mengecas cepat (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mengecas perlahan (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> sehingga penuh)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Tukar pengguna"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Tukar pengguna, pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Pengguna semasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index d0eaccf..adfd9f8 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ဦးစားပေးမှု\nသာ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"နှိုးစက်များ\nသာ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"(<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> အပြည့် အထိ) အားသွင်းနေ"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"လျှင်မြန်စွာအားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"နှေးကွေးစွာ အားသွင်းခြင်း (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ပြည့်သည်အထိ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"အသုံးပြုသူကို ပြောင်းလဲရန်"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"အသုံးပြုသူကို ပြောင်းရန်၊ လက်ရှိ အသုံးပြုသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"လတ်တလော သုံးစွဲသူ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index e582039..ecfb7f2 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Bare\nPrioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Bare\nalarmer"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Lader (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Lader raskt (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Lader sakte (fulladet om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Bytt bruker"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Bytt bruker, gjeldende bruker er <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Gjeldende bruker: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index c3dc703..d997aff 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"प्राथमिकता \nमात्र"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"अलार्महरू \nमात्र"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण भएसम्म)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"छिटो चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"बिस्तारै चार्ज हुँदै (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> पूर्ण नभएसम्म)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"प्रयोगकर्ता फेर्नुहोस्"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"प्रयोगकर्ता, हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g> मा स्विच गर्नुहोस्"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"हालको प्रयोगकर्ता <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 79f3333..c6bab06 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Alleen\nprioriteit"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Alleen\nalarmen"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Snel opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Langzaam opladen (vol over <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Gebruiker wijzigen"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schakelen tussen gebruikers, huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Huidige gebruiker <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index ef3d2f3..74e5fcb 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ਕੇਵਲ\nਤਰਜੀਹੀ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ਕੇਵਲ\nਅਲਾਰਮ"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ਚਾਰਜਿੰਗ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰਾ ਹੋਣ ਤੱਕ)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ਤੇਜ਼ੀ ਨਾਲ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"ਹੌਲੀ-ਹੌਲੀ ਚਾਰਜ ਹੋ ਰਹੀ ਹੈ (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ਪੂਰੀ ਹੋਣ ਤੱਕ)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"ਉਪਭੋਗਤਾ ਸਵਿਚ ਕਰੋ"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"ਉਪਭੋਗਤਾ, ਵਰਤਮਾਨ ਉਪਭੋਗਤਾ ਸਵਿਚ ਕਰੋ<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ਮੌਜੂਦਾ ਉਪਭੋਗਤਾ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 8c2c5c4..e04fd71 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Tylko\npriorytetowe"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Tylko\nalarmy"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Ładuje się (pełne naładowanie za <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Szybkie ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Wolne ładowanie (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do końca)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Przełącz użytkownika"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Przełącz użytkownika. Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Bieżący użytkownik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 3803b812..2a8e3ab 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 12609c7..8453e5b 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Apenas\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Apenas\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"A carregar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"A carregar rapid. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"A carregar lentam. (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até à carga máxima)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Mudar utilizador"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Mudar de utilizador; o utilizador atual é <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilizador atual: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 3803b812..2a8e3ab 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Somente\nprioridade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Somente\nalarmes"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Carregando (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> até concluir)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Carregando rapidamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Carregando lentamente (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> para conclusão)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Trocar usuário"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Alternar usuário. Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Usuário atual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index bb8f2c3..d85e791 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -326,6 +326,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Numai\ncu prioritate"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Numai\nalarme"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Se încarcă (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Se încarcă rapid (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Se încarcă lent (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> până la finalizare)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Comutați între utilizatori"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Schimbați utilizatorul (utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Utilizator actual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 9609f40..39d8617 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -329,6 +329,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Только\nважные"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Только\nбудильник"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Зарядка батареи (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Быстрая зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Медленная зарядка (осталось <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Сменить пользователя."</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Сменить аккаунт. Вход выполнен под именем <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>."</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Выбран аккаунт пользователя <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index 9e78834..51bb047 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ප්‍රමුඛතා\nපමණි"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"ඇඟවීම්\nපමණි"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"ඉක්මනින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"සෙමින් ආරෝපණය වෙමින් (සම්පුර්ණ වන තෙක් <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"පරිශීලක මාරුව"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"පරිශීලකයා මාරු කරන්න,දැන් සිටින පරිශීලකයා <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"වත්මන් පරිශීලක <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 2e41b29..2886e36 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -329,6 +329,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Iba\nprioritné"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Iba\nbudíky"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nabíja sa (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Nabíja sa rýchlo (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Nabíja sa pomaly (úplné nabitie o <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Prepnutie používateľa"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Prepnúť používateľa (súčasný používateľ: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuálny používateľ <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 4dffcfa..e325ef1 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Samo\nprednostno"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Samo\nalarmi"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hitro polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Počasno polnjenje (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> do napolnjenosti)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Preklop med uporabniki"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Preklop med uporabniki, trenutni uporabnik <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Trenutni uporabnik: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index 20c3426..5bcf941 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Vetëm\nme prioritet"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Vetëm\nalarmet"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Po ngarkohet (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> deri sa të mbushet)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Po ngarkon me shpejtësi (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Po ngarkon me ngadalë (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> derisa të mbushet)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Ndërro përdorues"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Ndërro përdoruesin. Përdoruesi aktual është <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Përdoruesi aktual <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 1dcde3a..522b2af 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -326,6 +326,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Само\nприорит. прекиди"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Само\nаларми"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Пуњење (пун је за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Брзо се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Споро се пуни (напуниће се за <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Замени корисника"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Промените корисника, актуелни корисник је <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Актуелни корисник <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 0abeb1e..d91335c 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Endast\nprioriterade"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Endast\nalarm"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Laddar (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> tills batteriet är fulladdat)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Laddas snabbt (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Laddas sakta (batteriet fulladdat om <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Byt användare"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Byt användare. Aktuell användare: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Aktuell användare <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index d000004..1cf4293 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Kipaumbele\npekee"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Kengele\npekee"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Inachaji (Imebakisha <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ijae)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Inachaji kwa kasi (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Inachaji pole pole (itajaa baada ya <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Badili mtumiaji"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Badili mtumiaji, mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Mtumiaji wa sasa <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-sw600dp-land/dimens.xml b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
index 3a62ad9..f084bc2 100644
--- a/packages/SystemUI/res/values-sw600dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp-land/dimens.xml
@@ -16,12 +16,6 @@
 */
 -->
 <resources>
-    <!-- Recent Applications parameters -->
-    <dimen name="status_bar_recents_app_label_width">190dip</dimen>
-
-    <!-- The side padding for the task stack as a percentage of the width. -->
-    <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.25</item>
-
     <fraction name="keyguard_clock_y_fraction_max">37%</fraction>
     <fraction name="keyguard_clock_y_fraction_min">20%</fraction>
 
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index 83477c0..4f6d209 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -32,9 +32,4 @@
 
     <!-- Set to true to enable the user switcher on the keyguard. -->
     <bool name="config_keyguardUserSwitcher">true</bool>
-
-    <!-- Transposes the search bar layout in landscape. -->
-    <bool name="recents_has_transposed_search_bar">true</bool>
-    <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
-    <bool name="recents_has_transposed_nav_bar">false</bool>
 </resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 1af4ab1..49dbac2 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -32,10 +32,6 @@
     <!-- The width of the view containing the menu/ime navigation bar icons -->
     <dimen name="navigation_extra_key_width">48dip</dimen>
 
-    <!-- Size of application thumbnail -->
-    <dimen name="status_bar_recents_thumbnail_width">200dp</dimen>
-    <dimen name="status_bar_recents_thumbnail_height">177dp</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>
 
@@ -43,12 +39,6 @@
     <!-- On tablets this is just the close_handle_height -->
     <dimen name="peek_height">@dimen/close_handle_height</dimen>
 
-    <!-- The side padding for the task stack as a percentage of the width. -->
-    <item name="recents_stack_width_padding_percentage" format="float" type="dimen">0.075</item>
-
-    <!-- The height of the search bar space. -->
-    <dimen name="recents_search_bar_space_height">72dp</dimen>
-
     <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
          max value is used when no notifications are displaying, and the min value is when the
          highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values-sw720dp/config.xml b/packages/SystemUI/res/values-sw720dp/config.xml
index fbeadcd..64e2760e 100644
--- a/packages/SystemUI/res/values-sw720dp/config.xml
+++ b/packages/SystemUI/res/values-sw720dp/config.xml
@@ -22,27 +22,8 @@
 <resources>
     <integer name="status_bar_config_maxNotificationIcons">5</integer>
 
-    <!-- Whether we're using the tablet-optimized recents interface (we use this
-     value at runtime for some things) -->
-    <bool name="config_recents_interface_for_tablets">true</bool>
-
-    <!-- Whether recents thumbnails should stretch in both x and y to fill their
-     ImageView -->
-    <bool name="config_recents_thumbnail_image_fits_to_xy">true</bool>
-
-    <!-- Min alpha % that recent items will fade to while being dismissed -->
-    <integer name="config_recent_item_min_alpha">0</integer>
-
-    <!-- Transposes the search bar layout in landscape -->
-    <bool name="recents_transpose_search_layout_with_orientation">false</bool>
-
     <!-- The maximum count of notifications on Keyguard. The rest will be collapsed in an overflow
          card. -->
     <integer name="keyguard_max_notification_count">5</integer>
-
-    <!-- Transposes the search bar layout in landscape. -->
-    <bool name="recents_has_transposed_search_bar">false</bool>
-    <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
-    <bool name="recents_has_transposed_nav_bar">false</bool>
 </resources>
 
diff --git a/packages/SystemUI/res/values-sw720dp/dimens.xml b/packages/SystemUI/res/values-sw720dp/dimens.xml
index dd158c2..7cee381 100644
--- a/packages/SystemUI/res/values-sw720dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp/dimens.xml
@@ -29,42 +29,9 @@
     <!-- Bottom margin (from display edge) for status bar panels -->
     <dimen name="panel_float">56dp</dimen>
 
-    <!-- Recent Applications parameters -->
-    <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">28dp</dimen>
-    <!-- Upper width limit for application icon -->
-    <dimen name="status_bar_recents_app_icon_max_width">64dp</dimen>
-    <!-- Upper height limit for application icon -->
-    <dimen name="status_bar_recents_app_icon_max_height">64dp</dimen>
-
-    <!-- Size of application icon -->
-    <dimen name="status_bar_recents_thumbnail_width">208dp</dimen>
-    <dimen name="status_bar_recents_thumbnail_height">130dp</dimen>
-
-    <!-- Width of recents panel -->
-    <dimen name="status_bar_recents_width">600dp</dimen>
-    <!-- Padding for text descriptions -->
-    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
-    <!-- Size of application label text -->
-    <dimen name="status_bar_recents_app_label_text_size">18dip</dimen>
-    <!-- Size of application description text -->
-    <dimen name="status_bar_recents_app_description_text_size">18dip</dimen>
-    <!-- Width of application label text -->
-    <dimen name="status_bar_recents_app_label_width">97dip</dimen>
-    <!-- Left margin for application label -->
-    <dimen name="status_bar_recents_app_label_left_margin">16dip</dimen>
-    <!-- Size of fading edge for text -->
-    <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen>
-    <!-- Size of fading edge for scrolling -->
-    <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen>
-
     <!-- The radius of the rounded corners on a task view. -->
     <dimen name="recents_task_view_rounded_corners_radius">3dp</dimen>
 
-    <!-- Where to place the app icon over the thumbnail -->
-    <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
-    <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
-
     <!-- The fraction of the screen height where the clock on the Keyguard has its center. The
      max value is used when no notifications are displaying, and the min value is when the
      highest possible number of notifications are showing. -->
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index 7b1ded3..670bccc 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"முன்னுரிமைகள்\nமட்டும்"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"அலாரங்கள்\nமட்டும்"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"சார்ஜாகிறது (முழு சார்ஜிற்கு <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ஆகும்)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"வேகமாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"மெதுவாக சார்ஜாகிறது (முழு சார்ஜிற்கு: <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"பயனரை மாற்று"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"பயனரை மாற்று, தற்போதைய பயனர் <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"தற்போதைய பயனர்: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 06762bd..bbd9979 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"ప్రాధాన్యమైనవి\nమాత్రమే"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"అలారాలు\nమాత్రమే"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"ఛార్జ్ అవుతోంది (పూర్తిగా నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"వేగంగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"నెమ్మదిగా ఛార్జ్ అవుతోంది (నిండటానికి <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"వినియోగదారుని మార్చు"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"వినియోగదారుని మార్చు, ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ప్రస్తుత వినియోగదారు <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 52c7af7..2486519 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"เฉพาะเรื่อง\nสำคัญ"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"เฉพาะปลุก\nเท่านั้น"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"กำลังชาร์จ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> เต็ม)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"กำลังชาร์จอย่างรวดเร็ว (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"กำลังชาร์จอย่างช้าๆ (อีก <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> จะเต็ม)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"สลับผู้ใช้"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"เปลี่ยนผู้ใช้จากผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"ผู้ใช้ปัจจุบัน <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 66056d1..3d1243e 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Priyoridad\nlang"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Mga alarm\nlang"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Nagtsa-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang mapuno)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Mabilis mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Mabagal mag-charge (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> hanggang sa mapuno)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Magpalit ng user"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Magpalit ng user, kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Kasalukuyang user <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 49edb57..4dadfbc 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Yalnızca\nöncelik"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Yalnızca\nalarmlar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Şarj oluyor (tamamen dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Hızlı şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Yavaş şarj oluyor (tam dolmasına <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> kaldı)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Kullanıcı değiştirme"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Kullanıcı değiştir. Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Geçerli kullanıcı: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9dde801..d158dbe 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Лише\nприорітетні"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Лише\nсигнали"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного зарядження)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Швидке заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Повільне заряджання (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> до повного заряду)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Змінити користувача"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Змінити користувача, поточний користувач – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Поточний користувач: <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index a4ef16a..f8d8c71 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"صرف\nترجیحی"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"صرف\nالارمز"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"چارج ہو رہا ہے (مکمل ہونے تک <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> باقی ہیں)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"تیزی سے چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"آہستہ چارج ہو رہا ہے (مکمل ہونے میں <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"صارف سوئچ کریں"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"صارف سوئچ کریں، موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"موجودہ صارف <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 04ec78b..0186809 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -82,7 +82,7 @@
     <string name="accessibility_home" msgid="8217216074895377641">"Uyga"</string>
     <string name="accessibility_menu" msgid="316839303324695949">"Menyu"</string>
     <string name="accessibility_recent" msgid="5208608566793607626">"Umumiy nazar"</string>
-    <string name="accessibility_search_light" msgid="1103867596330271848">"Izlash"</string>
+    <string name="accessibility_search_light" msgid="1103867596330271848">"Qidirish"</string>
     <string name="accessibility_camera_button" msgid="8064671582820358152">"Kamera"</string>
     <string name="accessibility_phone_button" msgid="6738112589538563574">"Telefon"</string>
     <string name="accessibility_voice_assist_button" msgid="487611083884852965">"Ovozli yordam"</string>
@@ -303,7 +303,7 @@
     <string name="expanded_header_battery_charging_with_time" msgid="457559884275395376">"<xliff:g id="CHARGING_TIME">%s</xliff:g>da to‘ladi"</string>
     <string name="expanded_header_battery_not_charging" msgid="4798147152367049732">"Quvvat olmayapti"</string>
     <string name="ssl_ca_cert_warning" msgid="9005954106902053641">"Tarmoq nazorat\nostida bo‘lishi mumkin"</string>
-    <string name="description_target_search" msgid="3091587249776033139">"Izlash"</string>
+    <string name="description_target_search" msgid="3091587249776033139">"Qidirish"</string>
     <string name="description_direction_up" msgid="7169032478259485180">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun yuqoriga suring."</string>
     <string name="description_direction_left" msgid="7207478719805562165">"<xliff:g id="TARGET_DESCRIPTION">%s</xliff:g> uchun chapga suring."</string>
     <string name="zen_priority_introduction" msgid="3070506961866919502">"Turli ovoz va tebranishlar endi sizni bezovta qilmaydi. Biroq uyg‘otkich signallari, eslatmalar, tadbirlar haqidagi bildirishnomalar va siz tanlagan abonentlardan kelgan qo‘ng‘iroqlar bundan mustasno."</string>
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Faqat\nmuhimlar"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Faqat\nsignallar"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Quvvat olmoqda (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>da to‘ladi)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Tez quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sekin quvvat olmoqda (to‘lishiga <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> qoldi)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Foydalanuvchini almashtirish"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Foydalanuvchini o‘zgartirish. Joriy foydalanuvchi – <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Joriy foydalanuvchi <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index 460d57a..49b5d1d 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Chỉ\nưu tiên"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Chỉ\nbáo thức"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Đang sạc (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho đến khi đầy)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Sạc nhanh (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Sạc chậm (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> cho tới khi đầy)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Chuyển đổi người dùng"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Chuyển người dùng, người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Người dùng hiện tại <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 4d70f24..93ed5ca 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"仅限\n优先打扰"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"仅限\n闹钟"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"正在充电(还需<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>充满)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充电(还需 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在慢速充电(还需 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>才能充满)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切换用户"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切换用户,当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"当前用户为<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index f7cac90e..2196111 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅限\n優先"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅限\n鬧鐘"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"正在快速充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"正在緩慢充電 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後完成充電)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"目前的使用者是 <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 369172f3..fe4fe06 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -327,6 +327,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"僅允許\n優先通知"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"僅允許\n鬧鐘"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"充電中 (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>後充飽)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"快速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"慢速充電中 (充飽需要 <xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g>)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"切換使用者"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"切換使用者,目前使用者是<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"目前使用者是「<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>」"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 2a14a9f..2f068af 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -325,6 +325,8 @@
     <string name="interruption_level_priority_twoline" msgid="1564715335217164124">"Okubalulekile\nkuphela"</string>
     <string name="interruption_level_alarms_twoline" msgid="3266909566410106146">"Ama-alamu\nkuphela"</string>
     <string name="keyguard_indication_charging_time" msgid="1757251776872835768">"Iyashaja (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
+    <string name="keyguard_indication_charging_time_fast" msgid="9018981952053914986">"Iyashaja ngokushesha (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
+    <string name="keyguard_indication_charging_time_slowly" msgid="955252797961724952">"Iyashaja kancane (<xliff:g id="CHARGING_TIME_LEFT">%s</xliff:g> ize igcwale)"</string>
     <string name="accessibility_multi_user_switch_switcher" msgid="7305948938141024937">"Shintsha umsebenzisi"</string>
     <string name="accessibility_multi_user_switch_switcher_with_current" msgid="8434880595284601601">"Shintsha umsebenzisi, umsebenzisi wamanje ngu-<xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
     <string name="accessibility_multi_user_switch_inactive" msgid="1424081831468083402">"Umsebenzisi wamanje <xliff:g id="CURRENT_USER_NAME">%s</xliff:g>"</string>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index da21084..f40f0d9 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -24,11 +24,8 @@
     <color name="system_bar_background_semi_transparent">#66000000</color> <!-- 40% black -->
     <color name="system_bar_background_transparent">#00000000</color>
     <color name="notification_panel_solid_background">#ff000000</color>
-    <drawable name="status_bar_recents_app_thumbnail_background">#88000000</drawable>
-    <color name="status_bar_recents_app_label_color">#ffffffff</color>
     <drawable name="status_bar_notification_row_background_color">#ff090909</drawable>
     <color name="notification_list_shadow_top">#80000000</color>
-    <drawable name="recents_callout_line">#99ffffff</drawable>
     <drawable name="heads_up_notification_bg_pressed">#ff33B5E5</drawable>
     <color name="batterymeter_frame_color">#4DFFFFFF</color><!-- 30% white -->
     <color name="batterymeter_charge_color">#FFFFFFFF</color>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 8da1148..1d19589 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -20,15 +20,6 @@
 <!-- These resources are around just to allow their values to be customized
      for different hardware and product builds. -->
 <resources>
-
-    <!-- Whether we're using the tablet-optimized recents interface (we use this
-     value at runtime for some things) -->
-    <bool name="config_recents_interface_for_tablets">false</bool>
-
-    <!-- Whether recents thumbnails should stretch in both x and y to fill their
-     ImageView -->
-    <bool name="config_recents_thumbnail_image_fits_to_xy">false</bool>
-
     <!-- Whether recents should use hardware layers for its taskviews. This flag can be enabled
     for devices where the java drawing of round rects may be slow -->
     <bool name="config_recents_use_hardware_layers">false</bool>
@@ -46,9 +37,6 @@
          certain GPU's and thus can be turned off with only minimal visual impact. -->
     <bool name="config_notifications_round_rect_clipping">true</bool>
 
-    <!-- The theme to use for RecentsActivity. -->
-    <item type="style" name="config_recents_activity_theme">@style/RecentsTheme.Wallpaper</item>
-
     <!-- Control whether status bar should distinguish HSPA data icon form UMTS
     data icon on devices -->
     <bool name="config_hspa_data_distinguishable">false</bool>
@@ -92,10 +80,6 @@
     <!-- The length of the vibration when the notification pops open. -->
     <integer name="one_finger_pop_duration_ms">10</integer>
 
-    <!-- Whether we're using the tablet-optimized recents interface (we use this
-     value at runtime for some things) -->
-    <integer name="status_bar_recents_bg_gradient_degrees">90</integer>
-
     <!-- decay duration (from size_max -> size), in ms -->
     <integer name="navigation_bar_deadzone_hold">333</integer>
     <integer name="navigation_bar_deadzone_decay">333</integer>
@@ -205,12 +189,6 @@
     <!-- The delay to enforce between each alt-tab key press. -->
     <integer name="recents_alt_tab_key_delay">200</integer>
 
-    <!-- Transposes the search bar layout in landscape. -->
-    <bool name="recents_has_transposed_search_bar">true</bool>
-
-    <!-- Transposes the nav bar in landscape (only used for purposes of layout). -->
-    <bool name="recents_has_transposed_nav_bar">true</bool>
-
     <!-- Svelte specific logic, see RecentsConfiguration.SVELTE_* constants. -->
     <integer name="recents_svelte_level">0</integer>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 96a77256..abfd863 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -16,45 +16,6 @@
 */
 -->
 <resources>
-    <!-- Recent Applications parameters -->
-    <!-- Upper width limit for application icon -->
-    <dimen name="status_bar_recents_app_icon_max_width">48dp</dimen>
-    <!-- Upper height limit for application icon -->
-    <dimen name="status_bar_recents_app_icon_max_height">48dp</dimen>
-
-    <!-- Size of application thumbnail -->
-    <dimen name="status_bar_recents_thumbnail_width">164dp</dimen>
-    <dimen name="status_bar_recents_thumbnail_height">145dp</dimen>
-    <dimen name="status_bar_recents_thumbnail_bg_padding">4dp</dimen>
-
-    <!-- Size of application label text -->
-    <dimen name="status_bar_recents_app_label_text_size">14dip</dimen>
-    <!-- Size of application description text -->
-    <dimen name="status_bar_recents_app_description_text_size">14dip</dimen>
-    <!-- Size of fading edge for text -->
-    <dimen name="status_bar_recents_text_fading_edge_length">20dip</dimen>
-    <!-- Size of fading edge for scrolling -->
-    <dimen name="status_bar_recents_scroll_fading_edge_length">10dip</dimen>
-    <!-- Margin between recents container and glow on the right -->
-    <dimen name="status_bar_recents_right_glow_margin">100dip</dimen>
-    <!-- How far the thumbnail for a recent app appears from left edge -->
-    <dimen name="status_bar_recents_thumbnail_left_margin">20dp</dimen>
-    <!-- Padding for text descriptions -->
-    <dimen name="status_bar_recents_text_description_padding">8dp</dimen>
-    <!-- Width of application label text -->
-    <dimen name="status_bar_recents_app_label_width">88dip</dimen>
-    <!-- Left margin of application label text -->
-    <dimen name="status_bar_recents_app_label_left_margin">0dip</dimen>
-    <!-- Padding between recents items -->
-    <dimen name="status_bar_recents_item_padding">0dip</dimen>
-    <!-- When recents first appears, how far the icon and label of the primary activity
-         travel -->
-    <dimen name="status_bar_recents_app_icon_translate_distance">35dip</dimen>
-
-    <!-- Where to place the app icon over the thumbnail -->
-    <dimen name="status_bar_recents_app_icon_left_margin">0dp</dimen>
-    <dimen name="status_bar_recents_app_icon_top_margin">8dp</dimen>
-
     <!-- Amount to offset bottom of notification peek window from top of status bar. -->
     <dimen name="peek_window_y_offset">-12dp</dimen>
 
diff --git a/packages/SystemUI/res/values/donottranslate.xml b/packages/SystemUI/res/values/donottranslate.xml
index 351a1fd..30ff704 100644
--- a/packages/SystemUI/res/values/donottranslate.xml
+++ b/packages/SystemUI/res/values/donottranslate.xml
@@ -20,4 +20,10 @@
     <!-- Date format for display: should match the lockscreen in /policy.  -->
     <string name="system_ui_date_pattern">@*android:string/system_ui_date_pattern</string>
 
+    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+    <item type="string" name="keyguard_indication_charging_time_fast_if_translated">@string/keyguard_indication_charging_time</item>
+
+    <!-- DO NOT TRANSLATE - temporary hack to show the speed-less label if no translation is available -->
+    <item type="string" name="keyguard_indication_charging_time_slowly_if_translated">@string/keyguard_indication_charging_time</item>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index db1e688..d567e97 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -793,6 +793,12 @@
     <!-- Indication on the keyguard that is shown when the device is charging. [CHAR LIMIT=40]-->
     <string name="keyguard_indication_charging_time">Charging (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
 
+    <!-- Indication on the keyguard that is shown when the device is charging rapidly. Should match keyguard_plugged_in_charging_fast [CHAR LIMIT=40]-->
+    <string name="keyguard_indication_charging_time_fast">Charging rapidly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+
+    <!-- Indication on the keyguard that is shown when the device is charging slowly. Should match keyguard_plugged_in_charging_slowly [CHAR LIMIT=40]-->
+    <string name="keyguard_indication_charging_time_slowly">Charging slowly (<xliff:g id="charging_time_left" example="4 hours and 2 minutes">%s</xliff:g> until full)</string>
+
     <!-- Related to user switcher --><skip/>
 
     <!-- Accessibility label for the button that opens the user switcher. -->
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
new file mode 100755
index 0000000..3eb1271
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterDrawable.java
@@ -0,0 +1,464 @@
+/*
+ * Copyright (C) 2015 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.animation.ArgbEvaluator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.content.res.TypedArray;
+import android.database.ContentObserver;
+import android.graphics.*;
+import android.graphics.drawable.Drawable;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.provider.Settings;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+public class BatteryMeterDrawable extends Drawable implements DemoMode,
+        BatteryController.BatteryStateChangeCallback {
+
+    private static final float ASPECT_RATIO = 9.5f / 14.5f;
+    public static final String TAG = BatteryMeterDrawable.class.getSimpleName();
+    public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
+
+    private static final boolean SINGLE_DIGIT_PERCENT = false;
+
+    private static final int FULL = 96;
+
+    private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
+
+    private final int[] mColors;
+
+    private boolean mShowPercent;
+    private float mButtonHeightFraction;
+    private float mSubpixelSmoothingLeft;
+    private float mSubpixelSmoothingRight;
+    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
+    private float mTextHeight, mWarningTextHeight;
+    private int mIconTint = Color.WHITE;
+
+    private int mHeight;
+    private int mWidth;
+    private String mWarningString;
+    private final int mCriticalLevel;
+    private int mChargeColor;
+    private final float[] mBoltPoints;
+    private final Path mBoltPath = new Path();
+
+    private final RectF mFrame = new RectF();
+    private final RectF mButtonFrame = new RectF();
+    private final RectF mBoltFrame = new RectF();
+
+    private final Path mShapePath = new Path();
+    private final Path mClipPath = new Path();
+    private final Path mTextPath = new Path();
+
+    private BatteryController mBatteryController;
+    private boolean mPowerSaveEnabled;
+
+    private int mDarkModeBackgroundColor;
+    private int mDarkModeFillColor;
+
+    private int mLightModeBackgroundColor;
+    private int mLightModeFillColor;
+
+    private final SettingObserver mSettingObserver = new SettingObserver();
+
+    private final Context mContext;
+    private final Handler mHandler;
+
+    private int mLevel = -1;
+    private boolean mPluggedIn;
+    private boolean mListening;
+
+    public BatteryMeterDrawable(Context context, Handler handler, int frameColor) {
+        mContext = context;
+        mHandler = handler;
+        final Resources res = context.getResources();
+        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
+        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
+
+        final int N = levels.length();
+        mColors = new int[2*N];
+        for (int i=0; i<N; i++) {
+            mColors[2*i] = levels.getInt(i, 0);
+            mColors[2*i+1] = colors.getColor(i, 0);
+        }
+        levels.recycle();
+        colors.recycle();
+        updateShowPercent();
+        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
+        mCriticalLevel = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
+        mButtonHeightFraction = context.getResources().getFraction(
+                R.fraction.battery_button_height_fraction, 1, 1);
+        mSubpixelSmoothingLeft = context.getResources().getFraction(
+                R.fraction.battery_subpixel_smoothing_left, 1, 1);
+        mSubpixelSmoothingRight = context.getResources().getFraction(
+                R.fraction.battery_subpixel_smoothing_right, 1, 1);
+
+        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mFramePaint.setColor(frameColor);
+        mFramePaint.setDither(true);
+        mFramePaint.setStrokeWidth(0);
+        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBatteryPaint.setDither(true);
+        mBatteryPaint.setStrokeWidth(0);
+        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
+
+        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
+        mTextPaint.setTypeface(font);
+        mTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mWarningTextPaint.setColor(mColors[1]);
+        font = Typeface.create("sans-serif", Typeface.BOLD);
+        mWarningTextPaint.setTypeface(font);
+        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
+
+        mChargeColor = context.getColor(R.color.batterymeter_charge_color);
+
+        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
+        mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
+        mBoltPoints = loadBoltPoints(res);
+
+        mDarkModeBackgroundColor =
+                context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
+        mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
+        mLightModeBackgroundColor =
+                context.getColor(R.color.light_mode_icon_color_dual_tone_background);
+        mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
+    }
+
+    public void startListening() {
+        mListening = true;
+        mContext.getContentResolver().registerContentObserver(
+                Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
+        if (mDemoMode) return;
+        mBatteryController.addStateChangedCallback(this);
+    }
+
+    public void stopListening() {
+        mListening = false;
+        mContext.getContentResolver().unregisterContentObserver(mSettingObserver);
+        if (mDemoMode) return;
+        mBatteryController.removeStateChangedCallback(this);
+    }
+
+    private void postInvalidate() {
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                invalidateSelf();
+            }
+        });
+    }
+
+    public void setBatteryController(BatteryController batteryController) {
+        mBatteryController = batteryController;
+        mPowerSaveEnabled = mBatteryController.isPowerSave();
+    }
+
+    @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        mLevel = level;
+        mPluggedIn = pluggedIn;
+
+        postInvalidate();
+    }
+
+    @Override
+    public void onPowerSaveChanged() {
+        mPowerSaveEnabled = mBatteryController.isPowerSave();
+        invalidateSelf();
+    }
+
+    private static float[] loadBoltPoints(Resources res) {
+        final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
+        int maxX = 0, maxY = 0;
+        for (int i = 0; i < pts.length; i += 2) {
+            maxX = Math.max(maxX, pts[i]);
+            maxY = Math.max(maxY, pts[i + 1]);
+        }
+        final float[] ptsF = new float[pts.length];
+        for (int i = 0; i < pts.length; i += 2) {
+            ptsF[i] = (float)pts[i] / maxX;
+            ptsF[i + 1] = (float)pts[i + 1] / maxY;
+        }
+        return ptsF;
+    }
+
+    @Override
+    public void setBounds(int left, int top, int right, int bottom) {
+        super.setBounds(left, top, right, bottom);
+        mHeight = bottom - top;
+        mWidth = right - left;
+        mWarningTextPaint.setTextSize(mHeight * 0.75f);
+        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
+    }
+
+    private void updateShowPercent() {
+        mShowPercent = 0 != Settings.System.getInt(mContext.getContentResolver(),
+                SHOW_PERCENT_SETTING, 0);
+    }
+
+    private int getColorForLevel(int percent) {
+
+        // If we are in power save mode, always use the normal color.
+        if (mPowerSaveEnabled) {
+            return mColors[mColors.length-1];
+        }
+        int thresh, color = 0;
+        for (int i=0; i<mColors.length; i+=2) {
+            thresh = mColors[i];
+            color = mColors[i+1];
+            if (percent <= thresh) {
+
+                // Respect tinting for "normal" level
+                if (i == mColors.length-2) {
+                    return mIconTint;
+                } else {
+                    return color;
+                }
+            }
+        }
+        return color;
+    }
+
+    public void setDarkIntensity(float darkIntensity) {
+        int backgroundColor = getBackgroundColor(darkIntensity);
+        int fillColor = getFillColor(darkIntensity);
+        mIconTint = fillColor;
+        mFramePaint.setColor(backgroundColor);
+        mBoltPaint.setColor(fillColor);
+        mChargeColor = fillColor;
+        invalidateSelf();
+    }
+
+    private int getBackgroundColor(float darkIntensity) {
+        return getColorForDarkIntensity(
+                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
+    }
+
+    private int getFillColor(float darkIntensity) {
+        return getColorForDarkIntensity(
+                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
+    }
+
+    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
+    }
+
+    @Override
+    public void draw(Canvas c) {
+        final int level = mLevel;
+
+        if (level == -1) return;
+
+        float drawFrac = (float) level / 100f;
+        final int height = mHeight;
+        final int width = (int) (ASPECT_RATIO * mHeight);
+        int px = (mWidth - width) / 2;
+
+        final int buttonHeight = (int) (height * mButtonHeightFraction);
+
+        mFrame.set(0, 0, width, height);
+        mFrame.offset(px, 0);
+
+        // button-frame: area above the battery body
+        mButtonFrame.set(
+                mFrame.left + Math.round(width * 0.25f),
+                mFrame.top,
+                mFrame.right - Math.round(width * 0.25f),
+                mFrame.top + buttonHeight);
+
+        mButtonFrame.top += mSubpixelSmoothingLeft;
+        mButtonFrame.left += mSubpixelSmoothingLeft;
+        mButtonFrame.right -= mSubpixelSmoothingRight;
+
+        // frame: battery body area
+        mFrame.top += buttonHeight;
+        mFrame.left += mSubpixelSmoothingLeft;
+        mFrame.top += mSubpixelSmoothingLeft;
+        mFrame.right -= mSubpixelSmoothingRight;
+        mFrame.bottom -= mSubpixelSmoothingRight;
+
+        // set the battery charging color
+        mBatteryPaint.setColor(mPluggedIn ? mChargeColor : getColorForLevel(level));
+
+        if (level >= FULL) {
+            drawFrac = 1f;
+        } else if (level <= mCriticalLevel) {
+            drawFrac = 0f;
+        }
+
+        final float levelTop = drawFrac == 1f ? mButtonFrame.top
+                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
+
+        // define the battery shape
+        mShapePath.reset();
+        mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
+        mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
+        mShapePath.lineTo(mButtonFrame.right, mFrame.top);
+        mShapePath.lineTo(mFrame.right, mFrame.top);
+        mShapePath.lineTo(mFrame.right, mFrame.bottom);
+        mShapePath.lineTo(mFrame.left, mFrame.bottom);
+        mShapePath.lineTo(mFrame.left, mFrame.top);
+        mShapePath.lineTo(mButtonFrame.left, mFrame.top);
+        mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
+
+        if (mPluggedIn) {
+            // define the bolt shape
+            final float bl = mFrame.left + mFrame.width() / 4.5f;
+            final float bt = mFrame.top + mFrame.height() / 6f;
+            final float br = mFrame.right - mFrame.width() / 7f;
+            final float bb = mFrame.bottom - mFrame.height() / 10f;
+            if (mBoltFrame.left != bl || mBoltFrame.top != bt
+                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
+                mBoltFrame.set(bl, bt, br, bb);
+                mBoltPath.reset();
+                mBoltPath.moveTo(
+                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+                for (int i = 2; i < mBoltPoints.length; i += 2) {
+                    mBoltPath.lineTo(
+                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
+                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
+                }
+                mBoltPath.lineTo(
+                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
+                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
+            }
+
+            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
+            boltPct = Math.min(Math.max(boltPct, 0), 1);
+            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
+                // draw the bolt if opaque
+                c.drawPath(mBoltPath, mBoltPaint);
+            } else {
+                // otherwise cut the bolt out of the overall shape
+                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
+            }
+        }
+
+        // compute percentage text
+        boolean pctOpaque = false;
+        float pctX = 0, pctY = 0;
+        String pctText = null;
+        if (!mPluggedIn && level > mCriticalLevel && mShowPercent) {
+            mTextPaint.setColor(getColorForLevel(level));
+            mTextPaint.setTextSize(height *
+                    (SINGLE_DIGIT_PERCENT ? 0.75f
+                            : (mLevel == 100 ? 0.38f : 0.5f)));
+            mTextHeight = -mTextPaint.getFontMetrics().ascent;
+            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
+            pctX = mWidth * 0.5f;
+            pctY = (mHeight + mTextHeight) * 0.47f;
+            pctOpaque = levelTop > pctY;
+            if (!pctOpaque) {
+                mTextPath.reset();
+                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
+                // cut the percentage text out of the overall shape
+                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
+            }
+        }
+
+        // draw the battery shape background
+        c.drawPath(mShapePath, mFramePaint);
+
+        // draw the battery shape, clipped to charging level
+        mFrame.top = levelTop;
+        mClipPath.reset();
+        mClipPath.addRect(mFrame,  Path.Direction.CCW);
+        mShapePath.op(mClipPath, Path.Op.INTERSECT);
+        c.drawPath(mShapePath, mBatteryPaint);
+
+        if (!mPluggedIn) {
+            if (level <= mCriticalLevel) {
+                // draw the warning text
+                final float x = mWidth * 0.5f;
+                final float y = (mHeight + mWarningTextHeight) * 0.48f;
+                c.drawText(mWarningString, x, y, mWarningTextPaint);
+            } else if (pctOpaque) {
+                // draw the percentage text
+                c.drawText(pctText, pctX, pctY, mTextPaint);
+            }
+        }
+    }
+
+    // Some stuff required by Drawable.
+    @Override
+    public void setAlpha(int alpha) {
+    }
+
+    @Override
+    public void setColorFilter(@Nullable ColorFilter colorFilter) {
+    }
+
+    @Override
+    public int getOpacity() {
+        return 0;
+    }
+
+    private boolean mDemoMode;
+
+    @Override
+    public void dispatchDemoCommand(String command, Bundle args) {
+        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
+            mBatteryController.removeStateChangedCallback(this);
+            mDemoMode = true;
+            if (mListening) {
+                mBatteryController.removeStateChangedCallback(this);
+            }
+        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
+            mDemoMode = false;
+            postInvalidate();
+            if (mListening) {
+                mBatteryController.addStateChangedCallback(this);
+            }
+        } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
+           String level = args.getString("level");
+           String plugged = args.getString("plugged");
+           if (level != null) {
+               mLevel = Math.min(Math.max(Integer.parseInt(level), 0), 100);
+           }
+           if (plugged != null) {
+               mPluggedIn = Boolean.parseBoolean(plugged);
+           }
+           postInvalidate();
+        }
+    }
+
+    private final class SettingObserver extends ContentObserver {
+        public SettingObserver() {
+            super(new Handler());
+        }
+
+        @Override
+        public void onChange(boolean selfChange, Uri uri) {
+            super.onChange(selfChange, uri);
+            updateShowPercent();
+            postInvalidate();
+        }
+    }
+
+}
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
old mode 100755
new mode 100644
index 95b58e5..6cb8da4
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -13,82 +13,19 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.android.systemui;
 
-import android.animation.ArgbEvaluator;
-import android.content.BroadcastReceiver;
 import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.database.ContentObserver;
-import android.graphics.Canvas;
-import android.graphics.Color;
-import android.graphics.Paint;
-import android.graphics.Path;
-import android.graphics.RectF;
-import android.graphics.Typeface;
-import android.net.Uri;
-import android.os.BatteryManager;
-import android.os.Bundle;
 import android.os.Handler;
-import android.provider.Settings;
 import android.util.AttributeSet;
-import android.view.View;
-
+import android.widget.ImageView;
 import com.android.systemui.statusbar.policy.BatteryController;
 
-public class BatteryMeterView extends View implements DemoMode,
-        BatteryController.BatteryStateChangeCallback {
-    public static final String TAG = BatteryMeterView.class.getSimpleName();
-    public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
-    public static final String SHOW_PERCENT_SETTING = "status_bar_show_battery_percent";
+public class BatteryMeterView extends ImageView implements BatteryController.BatteryStateChangeCallback {
 
-    private static final boolean SINGLE_DIGIT_PERCENT = false;
-
-    private static final int FULL = 96;
-
-    private static final float BOLT_LEVEL_THRESHOLD = 0.3f;  // opaque bolt below this fraction
-
-    private final int[] mColors;
-
-    private boolean mShowPercent;
-    private float mButtonHeightFraction;
-    private float mSubpixelSmoothingLeft;
-    private float mSubpixelSmoothingRight;
-    private final Paint mFramePaint, mBatteryPaint, mWarningTextPaint, mTextPaint, mBoltPaint;
-    private float mTextHeight, mWarningTextHeight;
-    private int mIconTint = Color.WHITE;
-
-    private int mHeight;
-    private int mWidth;
-    private String mWarningString;
-    private final int mCriticalLevel;
-    private int mChargeColor;
-    private final float[] mBoltPoints;
-    private final Path mBoltPath = new Path();
-
-    private final RectF mFrame = new RectF();
-    private final RectF mButtonFrame = new RectF();
-    private final RectF mBoltFrame = new RectF();
-
-    private final Path mShapePath = new Path();
-    private final Path mClipPath = new Path();
-    private final Path mTextPath = new Path();
-
+    private final BatteryMeterDrawable mDrawable;
     private BatteryController mBatteryController;
-    private boolean mPowerSaveEnabled;
-
-    private int mDarkModeBackgroundColor;
-    private int mDarkModeFillColor;
-
-    private int mLightModeBackgroundColor;
-    private int mLightModeFillColor;
-
-    private BatteryTracker mTracker = new BatteryTracker();
-    private final SettingObserver mSettingObserver = new SettingObserver();
 
     public BatteryMeterView(Context context) {
         this(context, null, 0);
@@ -101,326 +38,14 @@
     public BatteryMeterView(Context context, AttributeSet attrs, int defStyle) {
         super(context, attrs, defStyle);
 
-        final Resources res = context.getResources();
         TypedArray atts = context.obtainStyledAttributes(attrs, R.styleable.BatteryMeterView,
                 defStyle, 0);
         final int frameColor = atts.getColor(R.styleable.BatteryMeterView_frameColor,
                 context.getColor(R.color.batterymeter_frame_color));
-        TypedArray levels = res.obtainTypedArray(R.array.batterymeter_color_levels);
-        TypedArray colors = res.obtainTypedArray(R.array.batterymeter_color_values);
-
-        final int N = levels.length();
-        mColors = new int[2*N];
-        for (int i=0; i<N; i++) {
-            mColors[2*i] = levels.getInt(i, 0);
-            mColors[2*i+1] = colors.getColor(i, 0);
-        }
-        levels.recycle();
-        colors.recycle();
+        mDrawable = new BatteryMeterDrawable(context, new Handler(), frameColor);
         atts.recycle();
-        updateShowPercent();
-        mWarningString = context.getString(R.string.battery_meter_very_low_overlay_symbol);
-        mCriticalLevel = mContext.getResources().getInteger(
-                com.android.internal.R.integer.config_criticalBatteryWarningLevel);
-        mButtonHeightFraction = context.getResources().getFraction(
-                R.fraction.battery_button_height_fraction, 1, 1);
-        mSubpixelSmoothingLeft = context.getResources().getFraction(
-                R.fraction.battery_subpixel_smoothing_left, 1, 1);
-        mSubpixelSmoothingRight = context.getResources().getFraction(
-                R.fraction.battery_subpixel_smoothing_right, 1, 1);
 
-        mFramePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mFramePaint.setColor(frameColor);
-        mFramePaint.setDither(true);
-        mFramePaint.setStrokeWidth(0);
-        mFramePaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
-        mBatteryPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBatteryPaint.setDither(true);
-        mBatteryPaint.setStrokeWidth(0);
-        mBatteryPaint.setStyle(Paint.Style.FILL_AND_STROKE);
-
-        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        Typeface font = Typeface.create("sans-serif-condensed", Typeface.BOLD);
-        mTextPaint.setTypeface(font);
-        mTextPaint.setTextAlign(Paint.Align.CENTER);
-
-        mWarningTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mWarningTextPaint.setColor(mColors[1]);
-        font = Typeface.create("sans-serif", Typeface.BOLD);
-        mWarningTextPaint.setTypeface(font);
-        mWarningTextPaint.setTextAlign(Paint.Align.CENTER);
-
-        mChargeColor = context.getColor(R.color.batterymeter_charge_color);
-
-        mBoltPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
-        mBoltPaint.setColor(context.getColor(R.color.batterymeter_bolt_color));
-        mBoltPoints = loadBoltPoints(res);
-
-        mDarkModeBackgroundColor =
-                context.getColor(R.color.dark_mode_icon_color_dual_tone_background);
-        mDarkModeFillColor = context.getColor(R.color.dark_mode_icon_color_dual_tone_fill);
-        mLightModeBackgroundColor =
-                context.getColor(R.color.light_mode_icon_color_dual_tone_background);
-        mLightModeFillColor = context.getColor(R.color.light_mode_icon_color_dual_tone_fill);
-    }
-
-    @Override
-    public void onAttachedToWindow() {
-        super.onAttachedToWindow();
-
-        IntentFilter filter = new IntentFilter();
-        filter.addAction(Intent.ACTION_BATTERY_CHANGED);
-        filter.addAction(ACTION_LEVEL_TEST);
-        final Intent sticky = getContext().registerReceiver(mTracker, filter);
-        if (sticky != null) {
-            // preload the battery level
-            mTracker.onReceive(getContext(), sticky);
-        }
-        mBatteryController.addStateChangedCallback(this);
-        getContext().getContentResolver().registerContentObserver(
-                Settings.System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
-    }
-
-    @Override
-    public void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-
-        getContext().unregisterReceiver(mTracker);
-        mBatteryController.removeStateChangedCallback(this);
-        getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
-    }
-
-    public void setBatteryController(BatteryController batteryController) {
-        mBatteryController = batteryController;
-        mPowerSaveEnabled = mBatteryController.isPowerSave();
-    }
-
-    @Override
-    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
-        // TODO: Use this callback instead of own broadcast receiver.
-    }
-
-    @Override
-    public void onPowerSaveChanged() {
-        mPowerSaveEnabled = mBatteryController.isPowerSave();
-        invalidate();
-    }
-
-    private static float[] loadBoltPoints(Resources res) {
-        final int[] pts = res.getIntArray(R.array.batterymeter_bolt_points);
-        int maxX = 0, maxY = 0;
-        for (int i = 0; i < pts.length; i += 2) {
-            maxX = Math.max(maxX, pts[i]);
-            maxY = Math.max(maxY, pts[i + 1]);
-        }
-        final float[] ptsF = new float[pts.length];
-        for (int i = 0; i < pts.length; i += 2) {
-            ptsF[i] = (float)pts[i] / maxX;
-            ptsF[i + 1] = (float)pts[i + 1] / maxY;
-        }
-        return ptsF;
-    }
-
-    @Override
-    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
-        mHeight = h;
-        mWidth = w;
-        mWarningTextPaint.setTextSize(h * 0.75f);
-        mWarningTextHeight = -mWarningTextPaint.getFontMetrics().ascent;
-    }
-
-    private void updateShowPercent() {
-        mShowPercent = 0 != Settings.System.getInt(getContext().getContentResolver(),
-                SHOW_PERCENT_SETTING, 0);
-    }
-
-    private int getColorForLevel(int percent) {
-
-        // If we are in power save mode, always use the normal color.
-        if (mPowerSaveEnabled) {
-            return mColors[mColors.length-1];
-        }
-        int thresh, color = 0;
-        for (int i=0; i<mColors.length; i+=2) {
-            thresh = mColors[i];
-            color = mColors[i+1];
-            if (percent <= thresh) {
-
-                // Respect tinting for "normal" level
-                if (i == mColors.length-2) {
-                    return mIconTint;
-                } else {
-                    return color;
-                }
-            }
-        }
-        return color;
-    }
-
-    public void setDarkIntensity(float darkIntensity) {
-        int backgroundColor = getBackgroundColor(darkIntensity);
-        int fillColor = getFillColor(darkIntensity);
-        mIconTint = fillColor;
-        mFramePaint.setColor(backgroundColor);
-        mBoltPaint.setColor(fillColor);
-        mChargeColor = fillColor;
-        invalidate();
-    }
-
-    private int getBackgroundColor(float darkIntensity) {
-        return getColorForDarkIntensity(
-                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
-    }
-
-    private int getFillColor(float darkIntensity) {
-        return getColorForDarkIntensity(
-                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
-    }
-
-    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
-        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
-    }
-
-    @Override
-    public void draw(Canvas c) {
-        BatteryTracker tracker = mDemoMode ? mDemoTracker : mTracker;
-        final int level = tracker.level;
-
-        if (level == BatteryTracker.UNKNOWN_LEVEL) return;
-
-        float drawFrac = (float) level / 100f;
-        final int pt = getPaddingTop();
-        final int pl = getPaddingLeft();
-        final int pr = getPaddingRight();
-        final int pb = getPaddingBottom();
-        final int height = mHeight - pt - pb;
-        final int width = mWidth - pl - pr;
-
-        final int buttonHeight = (int) (height * mButtonHeightFraction);
-
-        mFrame.set(0, 0, width, height);
-        mFrame.offset(pl, pt);
-
-        // button-frame: area above the battery body
-        mButtonFrame.set(
-                mFrame.left + Math.round(width * 0.25f),
-                mFrame.top,
-                mFrame.right - Math.round(width * 0.25f),
-                mFrame.top + buttonHeight);
-
-        mButtonFrame.top += mSubpixelSmoothingLeft;
-        mButtonFrame.left += mSubpixelSmoothingLeft;
-        mButtonFrame.right -= mSubpixelSmoothingRight;
-
-        // frame: battery body area
-        mFrame.top += buttonHeight;
-        mFrame.left += mSubpixelSmoothingLeft;
-        mFrame.top += mSubpixelSmoothingLeft;
-        mFrame.right -= mSubpixelSmoothingRight;
-        mFrame.bottom -= mSubpixelSmoothingRight;
-
-        // set the battery charging color
-        mBatteryPaint.setColor(tracker.plugged ? mChargeColor : getColorForLevel(level));
-
-        if (level >= FULL) {
-            drawFrac = 1f;
-        } else if (level <= mCriticalLevel) {
-            drawFrac = 0f;
-        }
-
-        final float levelTop = drawFrac == 1f ? mButtonFrame.top
-                : (mFrame.top + (mFrame.height() * (1f - drawFrac)));
-
-        // define the battery shape
-        mShapePath.reset();
-        mShapePath.moveTo(mButtonFrame.left, mButtonFrame.top);
-        mShapePath.lineTo(mButtonFrame.right, mButtonFrame.top);
-        mShapePath.lineTo(mButtonFrame.right, mFrame.top);
-        mShapePath.lineTo(mFrame.right, mFrame.top);
-        mShapePath.lineTo(mFrame.right, mFrame.bottom);
-        mShapePath.lineTo(mFrame.left, mFrame.bottom);
-        mShapePath.lineTo(mFrame.left, mFrame.top);
-        mShapePath.lineTo(mButtonFrame.left, mFrame.top);
-        mShapePath.lineTo(mButtonFrame.left, mButtonFrame.top);
-
-        if (tracker.plugged) {
-            // define the bolt shape
-            final float bl = mFrame.left + mFrame.width() / 4.5f;
-            final float bt = mFrame.top + mFrame.height() / 6f;
-            final float br = mFrame.right - mFrame.width() / 7f;
-            final float bb = mFrame.bottom - mFrame.height() / 10f;
-            if (mBoltFrame.left != bl || mBoltFrame.top != bt
-                    || mBoltFrame.right != br || mBoltFrame.bottom != bb) {
-                mBoltFrame.set(bl, bt, br, bb);
-                mBoltPath.reset();
-                mBoltPath.moveTo(
-                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
-                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
-                for (int i = 2; i < mBoltPoints.length; i += 2) {
-                    mBoltPath.lineTo(
-                            mBoltFrame.left + mBoltPoints[i] * mBoltFrame.width(),
-                            mBoltFrame.top + mBoltPoints[i + 1] * mBoltFrame.height());
-                }
-                mBoltPath.lineTo(
-                        mBoltFrame.left + mBoltPoints[0] * mBoltFrame.width(),
-                        mBoltFrame.top + mBoltPoints[1] * mBoltFrame.height());
-            }
-
-            float boltPct = (mBoltFrame.bottom - levelTop) / (mBoltFrame.bottom - mBoltFrame.top);
-            boltPct = Math.min(Math.max(boltPct, 0), 1);
-            if (boltPct <= BOLT_LEVEL_THRESHOLD) {
-                // draw the bolt if opaque
-                c.drawPath(mBoltPath, mBoltPaint);
-            } else {
-                // otherwise cut the bolt out of the overall shape
-                mShapePath.op(mBoltPath, Path.Op.DIFFERENCE);
-            }
-        }
-
-        // compute percentage text
-        boolean pctOpaque = false;
-        float pctX = 0, pctY = 0;
-        String pctText = null;
-        if (!tracker.plugged && level > mCriticalLevel && mShowPercent) {
-            mTextPaint.setColor(getColorForLevel(level));
-            mTextPaint.setTextSize(height *
-                    (SINGLE_DIGIT_PERCENT ? 0.75f
-                            : (tracker.level == 100 ? 0.38f : 0.5f)));
-            mTextHeight = -mTextPaint.getFontMetrics().ascent;
-            pctText = String.valueOf(SINGLE_DIGIT_PERCENT ? (level/10) : level);
-            pctX = mWidth * 0.5f;
-            pctY = (mHeight + mTextHeight) * 0.47f;
-            pctOpaque = levelTop > pctY;
-            if (!pctOpaque) {
-                mTextPath.reset();
-                mTextPaint.getTextPath(pctText, 0, pctText.length(), pctX, pctY, mTextPath);
-                // cut the percentage text out of the overall shape
-                mShapePath.op(mTextPath, Path.Op.DIFFERENCE);
-            }
-        }
-
-        // draw the battery shape background
-        c.drawPath(mShapePath, mFramePaint);
-
-        // draw the battery shape, clipped to charging level
-        mFrame.top = levelTop;
-        mClipPath.reset();
-        mClipPath.addRect(mFrame,  Path.Direction.CCW);
-        mShapePath.op(mClipPath, Path.Op.INTERSECT);
-        c.drawPath(mShapePath, mBatteryPaint);
-
-        if (!tracker.plugged) {
-            if (level <= mCriticalLevel) {
-                // draw the warning text
-                final float x = mWidth * 0.5f;
-                final float y = (mHeight + mWarningTextHeight) * 0.48f;
-                c.drawText(mWarningString, x, y, mWarningTextPaint);
-            } else if (pctOpaque) {
-                // draw the percentage text
-                c.drawText(pctText, pctX, pctY, mTextPaint);
-            }
-        }
+        setImageDrawable(mDrawable);
     }
 
     @Override
@@ -428,116 +53,37 @@
         return false;
     }
 
-    private boolean mDemoMode;
-    private BatteryTracker mDemoTracker = new BatteryTracker();
+    @Override
+    public void onAttachedToWindow() {
+        super.onAttachedToWindow();
+        mBatteryController.addStateChangedCallback(this);
+        mDrawable.startListening();
+    }
 
     @Override
-    public void dispatchDemoCommand(String command, Bundle args) {
-        if (!mDemoMode && command.equals(COMMAND_ENTER)) {
-            mDemoMode = true;
-            mDemoTracker.level = mTracker.level;
-            mDemoTracker.plugged = mTracker.plugged;
-        } else if (mDemoMode && command.equals(COMMAND_EXIT)) {
-            mDemoMode = false;
-            postInvalidate();
-        } else if (mDemoMode && command.equals(COMMAND_BATTERY)) {
-           String level = args.getString("level");
-           String plugged = args.getString("plugged");
-           if (level != null) {
-               mDemoTracker.level = Math.min(Math.max(Integer.parseInt(level), 0), 100);
-           }
-           if (plugged != null) {
-               mDemoTracker.plugged = Boolean.parseBoolean(plugged);
-           }
-           postInvalidate();
-        }
+    public void onDetachedFromWindow() {
+        super.onDetachedFromWindow();
+        mBatteryController.removeStateChangedCallback(this);
+        mDrawable.stopListening();
     }
 
-    private final class BatteryTracker extends BroadcastReceiver {
-        public static final int UNKNOWN_LEVEL = -1;
-
-        // current battery status
-        int level = UNKNOWN_LEVEL;
-        String percentStr;
-        int plugType;
-        boolean plugged;
-        int health;
-        int status;
-        String technology;
-        int voltage;
-        int temperature;
-        boolean testmode = false;
-
-        @Override
-        public void onReceive(Context context, Intent intent) {
-            final String action = intent.getAction();
-            if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
-                if (testmode && ! intent.getBooleanExtra("testmode", false)) return;
-
-                level = (int)(100f
-                        * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
-                        / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
-
-                plugType = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, 0);
-                plugged = plugType != 0;
-                health = intent.getIntExtra(BatteryManager.EXTRA_HEALTH,
-                        BatteryManager.BATTERY_HEALTH_UNKNOWN);
-                status = intent.getIntExtra(BatteryManager.EXTRA_STATUS,
-                        BatteryManager.BATTERY_STATUS_UNKNOWN);
-                technology = intent.getStringExtra(BatteryManager.EXTRA_TECHNOLOGY);
-                voltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, 0);
-                temperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, 0);
-
-                setContentDescription(
-                        context.getString(R.string.accessibility_battery_level, level));
-                postInvalidate();
-            } else if (action.equals(ACTION_LEVEL_TEST)) {
-                testmode = true;
-                post(new Runnable() {
-                    int curLevel = 0;
-                    int incr = 1;
-                    int saveLevel = level;
-                    int savePlugged = plugType;
-                    Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
-                    @Override
-                    public void run() {
-                        if (curLevel < 0) {
-                            testmode = false;
-                            dummy.putExtra("level", saveLevel);
-                            dummy.putExtra("plugged", savePlugged);
-                            dummy.putExtra("testmode", false);
-                        } else {
-                            dummy.putExtra("level", curLevel);
-                            dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
-                                    : 0);
-                            dummy.putExtra("testmode", true);
-                        }
-                        getContext().sendBroadcast(dummy);
-
-                        if (!testmode) return;
-
-                        curLevel += incr;
-                        if (curLevel == 100) {
-                            incr *= -1;
-                        }
-                        postDelayed(this, 200);
-                    }
-                });
-            }
-        }
+    @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        setContentDescription(
+                getContext().getString(R.string.accessibility_battery_level, level));
     }
 
-    private final class SettingObserver extends ContentObserver {
-        public SettingObserver() {
-            super(new Handler());
-        }
+    @Override
+    public void onPowerSaveChanged() {
 
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            super.onChange(selfChange, uri);
-            updateShowPercent();
-            postInvalidate();
-        }
     }
 
+    public void setBatteryController(BatteryController mBatteryController) {
+        this.mBatteryController = mBatteryController;
+        mDrawable.setBatteryController(mBatteryController);
+    }
+
+    public void setDarkIntensity(float f) {
+        mDrawable.setDarkIntensity(f);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
index 33f6564..6207324 100644
--- a/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/SwipeHelper.java
@@ -34,6 +34,8 @@
 import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
 
+import com.android.systemui.classifier.FalsingManager;
+
 public class SwipeHelper implements Gefingerpoken {
     static final String TAG = "com.android.systemui.SwipeHelper";
     private static final boolean DEBUG = false;
@@ -67,6 +69,7 @@
     private Handler mHandler;
     private int mSwipeDirection;
     private VelocityTracker mVelocityTracker;
+    private FalsingManager mFalsingManager;
 
     private float mInitialTouchPos;
     private boolean mDragging;
@@ -97,6 +100,7 @@
                 android.R.interpolator.fast_out_linear_in);
         mFalsingThreshold = context.getResources().getDimensionPixelSize(
                 R.dimen.swipe_helper_falsing_threshold);
+        mFalsingManager = FalsingManager.getInstance(context);
     }
 
     public void setLongPressListener(LongPressListener listener) {
@@ -449,8 +453,13 @@
                     boolean childSwipedFastEnough = (Math.abs(velocity) > escapeVelocity) &&
                             (Math.abs(velocity) > Math.abs(perpendicularVelocity)) &&
                             (velocity > 0) == (getTranslation(mCurrAnimView) > 0);
-                    boolean falsingDetected = mCallback.isAntiFalsingNeeded()
-                            && !mTouchAboveFalsingThreshold;
+                    boolean falsingDetected = mCallback.isAntiFalsingNeeded();
+
+                    if (mFalsingManager.isClassiferEnabled()) {
+                        falsingDetected = falsingDetected && mFalsingManager.isFalseTouch();
+                    } else {
+                        falsingDetected = falsingDetected && !mTouchAboveFalsingThreshold;
+                    }
 
                     boolean dismissChild = mCallback.canChildBeDismissed(mCurrView)
                             && !falsingDetected && (childSwipedFastEnough || childSwipedFarEnough)
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
index 7449009..5bf251b 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIApplication.java
@@ -159,7 +159,9 @@
         if (mServicesStarted) {
             int len = mServices.length;
             for (int i = 0; i < len; i++) {
-                mServices[i].onConfigurationChanged(newConfig);
+                if (mServices[i] != null) {
+                    mServices[i].onConfigurationChanged(newConfig);
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
new file mode 100644
index 0000000..86bea87
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AccelerationClassifier.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+import android.view.MotionEvent;
+
+import java.util.HashMap;
+
+/**
+ * A classifier which looks at the speed and distance between successive points of a Stroke.
+ * It looks at two consecutive speeds between two points and calculates the ratio between them.
+ * The final result is the maximum of these values. It does the same for distances. If some speed
+ * or distance is equal to zero then the ratio between this and the next part is not calculated. To
+ * the duration of each part there is added one nanosecond so that it is always possible to
+ * calculate the speed of a part.
+ */
+public class AccelerationClassifier extends StrokeClassifier {
+    private final HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+    public AccelerationClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mStrokeMap.clear();
+        }
+
+        for (int i = 0; i < event.getPointerCount(); i++) {
+            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+            Point point = stroke.getPoints().get(stroke.getPoints().size() - 1);
+            if (mStrokeMap.get(stroke) == null) {
+                mStrokeMap.put(stroke, new Data(point));
+            } else {
+                mStrokeMap.get(stroke).addPoint(point);
+            }
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        Data data = mStrokeMap.get(stroke);
+        return SpeedRatioEvaluator.evaluate(data.maxSpeedRatio)
+                + DistanceRatioEvaluator.evaluate(data.maxDistanceRatio);
+    }
+
+    private static class Data {
+        public Point previousPoint;
+        public float previousSpeed;
+        public float previousDistance;
+        public float maxSpeedRatio;
+        public float maxDistanceRatio;
+
+        public Data(Point point) {
+            previousPoint = point;
+            previousSpeed = previousDistance = 0.0f;
+            maxDistanceRatio = maxSpeedRatio = 0.0f;
+        }
+
+        public void addPoint(Point point) {
+            float distance = previousPoint.dist(point);
+            float duration = (float) (point.timeOffsetNano - previousPoint.timeOffsetNano + 1);
+            float speed = distance / duration;
+            if (previousDistance != 0.0f) {
+                maxDistanceRatio = Math.max(maxDistanceRatio, distance / previousDistance);
+            }
+
+            if (previousSpeed != 0.0f) {
+                maxSpeedRatio = Math.max(maxSpeedRatio, speed / previousSpeed);
+            }
+
+            previousDistance = distance;
+            previousSpeed = speed;
+            previousPoint = point;
+        }
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
new file mode 100644
index 0000000..a6ebc0b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesClassifier.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+import android.view.MotionEvent;
+
+import java.lang.Math;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A classifier which calculates the variance of differences between successive angles in a stroke.
+ * For each stroke it keeps its last three points. If some successive points are the same, it
+ * ignores the repetitions. If a new point is added, the classifier calculates the angle between
+ * the last three points. After that, it calculates the difference between this angle and the
+ * previously calculated angle. Then it calculates the variance of the differences from a stroke.
+ * To the differences there is artificially added value 0.0 and the difference between the first
+ * angle and PI (angles are in radians). It helps with strokes which have few points and punishes
+ * more strokes which are not smooth.
+ *
+ * This classifier also tries to split the stroke into two parts in the place in which the biggest
+ * angle is. It calculates the angle variance of the two parts and sums them up. The reason the
+ * classifier is doing this, is because some human swipes at the beginning go for a moment in one
+ * direction and then they rapidly change direction for the rest of the stroke (like a tick). The
+ * final result is the minimum of angle variance of the whole stroke and the sum of angle variances
+ * of the two parts split up. The classifier tries the tick option only if the first part is
+ * shorter than the second part.
+ *
+ * Additionally, the classifier classifies the angles as left angles (those angles which value is
+ * in [0.0, PI - ANGLE_DEVIATION) interval), straight angles
+ * ([PI - ANGLE_DEVIATION, PI + ANGLE_DEVIATION] interval) and right angles
+ * ((PI + ANGLE_DEVIATION, 2 * PI) interval) and then calculates the percentage of angles which are
+ * in the same direction (straight angles can be left angels or right angles)
+ */
+public class AnglesClassifier extends StrokeClassifier {
+    private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+    public AnglesClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mStrokeMap.clear();
+        }
+
+        for (int i = 0; i < event.getPointerCount(); i++) {
+            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+
+            if (mStrokeMap.get(stroke) == null) {
+                mStrokeMap.put(stroke, new Data());
+            }
+            mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1));
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        Data data = mStrokeMap.get(stroke);
+        return AnglesVarianceEvaluator.evaluate(data.getAnglesVariance())
+                + AnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
+    }
+
+    private static class Data {
+        private final float ANGLE_DEVIATION = (float) Math.PI / 20.0f;
+
+        private List<Point> mLastThreePoints = new ArrayList<>();
+        private float mFirstAngleVariance;
+        private float mPreviousAngle;
+        private float mBiggestAngle;
+        private float mSumSquares;
+        private float mSecondSumSquares;
+        private float mSum;
+        private float mSecondSum;
+        private float mCount;
+        private float mSecondCount;
+        private float mFirstLength;
+        private float mLength;
+        private float mAnglesCount;
+        private float mLeftAngles;
+        private float mRightAngles;
+        private float mStraightAngles;
+
+        public Data() {
+            mFirstAngleVariance = 0.0f;
+            mPreviousAngle = (float) Math.PI;
+            mBiggestAngle = 0.0f;
+            mSumSquares = mSecondSumSquares = 0.0f;
+            mSum = mSecondSum = 0.0f;
+            mCount = mSecondCount = 1.0f;
+            mLength = mFirstLength = 0.0f;
+            mAnglesCount = mLeftAngles = mRightAngles = mStraightAngles = 0.0f;
+        }
+
+        public void addPoint(Point point) {
+            // Checking if the added point is different than the previously added point
+            // Repetitions are being ignored so that proper angles are calculated.
+            if (mLastThreePoints.isEmpty()
+                    || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) {
+                if (!mLastThreePoints.isEmpty()) {
+                    mLength += mLastThreePoints.get(mLastThreePoints.size() - 1).dist(point);
+                }
+                mLastThreePoints.add(point);
+                if (mLastThreePoints.size() == 4) {
+                    mLastThreePoints.remove(0);
+
+                    float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
+                            mLastThreePoints.get(2));
+
+                    mAnglesCount++;
+                    if (angle < Math.PI - ANGLE_DEVIATION) {
+                        mLeftAngles++;
+                    } else if (angle <= Math.PI + ANGLE_DEVIATION) {
+                        mStraightAngles++;
+                    } else {
+                        mRightAngles++;
+                    }
+
+                    float difference = angle - mPreviousAngle;
+
+                    // If this is the biggest angle of the stroke so then we save the value of
+                    // the angle variance so far and start to count the values for the angle
+                    // variance of the second part.
+                    if (mBiggestAngle < angle) {
+                        mBiggestAngle = angle;
+                        mFirstLength = mLength;
+                        mFirstAngleVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+                        mSecondSumSquares = 0.0f;
+                        mSecondSum = 0.0f;
+                        mSecondCount = 1.0f;
+                    } else {
+                        mSecondSum += difference;
+                        mSecondSumSquares += difference * difference;
+                        mSecondCount += 1.0;
+                    }
+
+                    mSum += difference;
+                    mSumSquares += difference * difference;
+                    mCount += 1.0;
+                    mPreviousAngle = angle;
+                }
+            }
+        }
+
+        public float getAnglesVariance(float sumSquares, float sum, float count) {
+            return sumSquares / count - (sum / count) * (sum / count);
+        }
+
+        public float getAnglesVariance() {
+            float anglesVariance = getAnglesVariance(mSumSquares, mSum, mCount);
+            if (mFirstLength < mLength / 2f) {
+                anglesVariance = Math.min(anglesVariance, mFirstAngleVariance
+                        + getAnglesVariance(mSecondSumSquares, mSecondSum, mSecondCount));
+            }
+            return anglesVariance;
+        }
+
+        public float getAnglesPercentage() {
+            if (mAnglesCount == 0.0f) {
+                return 1.0f;
+            }
+            return (Math.max(mLeftAngles, mRightAngles) + mStraightAngles) / mAnglesCount;
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
similarity index 62%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
index c47d194..a0ceb29 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesPercentageEvaluator.java
@@ -11,11 +11,17 @@
  * 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.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class AnglesPercentageEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 1.00) evaluation++;
+        if (value < 0.95) evaluation++;
+        if (value < 0.90) evaluation++;
+        return evaluation;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
deleted file mode 100644
index 5cd914f..0000000
--- a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceClassifier.java
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2015 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.classifier;
-
-import android.hardware.SensorEvent;
-import android.view.MotionEvent;
-
-import java.lang.Math;
-
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-
-/**
- * A classifier which calculates the variance of differences between successive angles in a stroke.
- * For each stroke it keeps its last three points. If some successive points are the same, it ignores
- * the repetitions. If a new point is added, the classifier calculates the angle between the last
- * three points. After that it calculates the difference between this angle and the previously
- * calculated angle. The return value of the classifier is the variance of the differences
- * from a stroke. If there are multiple strokes created at once, the classifier sums up the
- * variances of all the strokes. Also the value is multiplied by HISTORY_FACTOR after each
- * INTERVAL milliseconds.
- */
-public class AnglesVarianceClassifier extends Classifier {
-    private final float INTERVAL = 10.0f;
-    private final float CLEAR_HISTORY = 500f;
-    private final float HISTORY_FACTOR = 0.9f;
-
-    private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
-    private float mValue;
-    private long mLastUpdate;
-
-    public AnglesVarianceClassifier(ClassifierData classifierData) {
-        mClassifierData = classifierData;
-        mValue = 0.0f;
-        mLastUpdate = System.currentTimeMillis();
-    }
-
-    @Override
-    public void onTouchEvent(MotionEvent event) {
-        int action = event.getActionMasked();
-
-        if (action == MotionEvent.ACTION_DOWN) {
-            mStrokeMap.clear();
-        }
-
-        for (int i = 0; i < event.getPointerCount(); i++) {
-            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
-
-            if (mStrokeMap.get(stroke) == null) {
-                mStrokeMap.put(stroke, new Data());
-            }
-            mStrokeMap.get(stroke).addPoint(stroke.getPoints().get(stroke.getPoints().size() - 1));
-
-            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
-                    || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
-                decayValue();
-                mValue += mStrokeMap.get(stroke).getAnglesVariance();
-            }
-        }
-    }
-
-    /**
-     * Decreases mValue through time
-     */
-    private void decayValue() {
-        long currentTimeMillis = System.currentTimeMillis();
-        if (currentTimeMillis - mLastUpdate > CLEAR_HISTORY) {
-            mValue = 0.0f;
-        } else {
-            mValue *= Math.pow(HISTORY_FACTOR, (float) (currentTimeMillis - mLastUpdate) / INTERVAL);
-        }
-        mLastUpdate = currentTimeMillis;
-    }
-
-    @Override
-    public void onSensorChanged(SensorEvent event) {
-    }
-
-    @Override
-    public float getFalseTouchEvaluation(int type) {
-        decayValue();
-        float currentValue = 0.0f;
-        for (Data data: mStrokeMap.values()) {
-            currentValue += data.getAnglesVariance();
-        }
-        return (float) (mValue + currentValue);
-    }
-
-    private class Data {
-        private List<Point> mLastThreePoints = new ArrayList<>();
-        private float mPreviousAngle;
-        private float mSumSquares;
-        private float mSum;
-        private float mCount;
-
-        public Data() {
-            mPreviousAngle = (float) Math.PI;
-            mSumSquares = 0.0f;
-            mSum = 0.0f;
-            mCount = 1.0f;
-        }
-
-        public void addPoint(Point point) {
-            // Checking if the added point is different than the previously added point
-            // Repetitions are being ignored so that proper angles are calculated.
-            if (mLastThreePoints.isEmpty()
-                    || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(point)) {
-                mLastThreePoints.add(point);
-                if (mLastThreePoints.size() == 4) {
-                    mLastThreePoints.remove(0);
-
-                    float angle = getAngle(mLastThreePoints.get(0), mLastThreePoints.get(1),
-                            mLastThreePoints.get(2));
-
-                    float difference = angle - mPreviousAngle;
-                    mSum += difference;
-                    mSumSquares += difference * difference;
-                    mCount += 1.0;
-                    mPreviousAngle = angle;
-                }
-            }
-        }
-
-        private float getAngle(Point a, Point b, Point c) {
-            float dist1 = a.dist(b);
-            float dist2 = b.dist(c);
-            float crossProduct = b.crossProduct(a, c);
-            float dotProduct = b.dotProduct(a, c);
-            float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2));
-            float angle = (float) Math.acos(cos);
-            if (crossProduct < 0.0) {
-                angle = 2.0f * (float) Math.PI - angle;
-            }
-            return angle;
-        }
-
-        public float getAnglesVariance() {
-            return mSumSquares / mCount + (mSum / mCount) * (mSum / mCount);
-        }
-    }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
new file mode 100644
index 0000000..99cc1a6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/AnglesVarianceEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class AnglesVarianceEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value > 0.05) evaluation++;
+        if (value > 0.10) evaluation++;
+        if (value > 0.20) evaluation++;
+        if (value > 0.40) evaluation++;
+        if (value > 0.80) evaluation++;
+        if (value > 1.50) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
index b76be14..89d20de 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Classifier.java
@@ -20,7 +20,7 @@
 import android.view.MotionEvent;
 
 /**
- * An interface for classifiers for touch and sensor events.
+ * An abstract class for classifiers for touch and sensor events.
  */
 public abstract class Classifier {
     public static final int QUICK_SETTINGS = 0;
@@ -30,6 +30,7 @@
     public static final int UNLOCK = 4;
     public static final int LEFT_AFFORDANCE = 5;
     public static final int RIGHT_AFFORDANCE = 6;
+    public static final int GENERIC = 7;
 
     /**
      * Contains all the information about touch events from which the classifier can query
@@ -47,11 +48,4 @@
      */
     public void onSensorChanged(SensorEvent event) {
     }
-
-    /**
-     * @param type the type of action for which this method is called
-     * @return a nonnegative value which is used to determine whether this a false touch. The
-     *         bigger the value the greater the chance that this a false touch.
-     */
-    public abstract float getFalseTouchEvaluation(int type);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
index 77b81d2..c83c74f6 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ClassifierData.java
@@ -19,32 +19,45 @@
 import android.util.SparseArray;
 import android.view.MotionEvent;
 
+import java.util.ArrayList;
+
 /**
  * Contains data which is used to classify interaction sequences on the lockscreen. It does, for
  * example, provide information on the current touch state.
  */
 public class ClassifierData {
     private SparseArray<Stroke> mCurrentStrokes = new SparseArray<>();
+    private ArrayList<Stroke> mEndingStrokes = new ArrayList<>();
+    private final float mDpi;
 
-    public ClassifierData() {
+    public ClassifierData(float dpi) {
+        mDpi = dpi;
     }
 
     public void update(MotionEvent event) {
+        mEndingStrokes.clear();
         int action = event.getActionMasked();
         if (action == MotionEvent.ACTION_DOWN) {
             mCurrentStrokes.clear();
         }
+
         for (int i = 0; i < event.getPointerCount(); i++) {
             int id = event.getPointerId(i);
             if (mCurrentStrokes.get(id) == null) {
-                mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano()));
+                mCurrentStrokes.put(id, new Stroke(event.getEventTimeNano(), mDpi));
             }
             mCurrentStrokes.get(id).addPoint(event.getX(i), event.getY(i),
                     event.getEventTimeNano());
+
+            if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL
+                    || (action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
+                mEndingStrokes.add(getStroke(id));
+            }
         }
     }
 
     public void cleanUp(MotionEvent event) {
+        mEndingStrokes.clear();
         int action = event.getActionMasked();
         for (int i = 0; i < event.getPointerCount(); i++) {
             int id = event.getPointerId(i);
@@ -56,6 +69,13 @@
     }
 
     /**
+     * @return the list of Strokes which are ending in the recently added MotionEvent
+     */
+    public ArrayList<Stroke> getEndingStrokes() {
+        return mEndingStrokes;
+    }
+
+    /**
      * @param id the id from MotionEvent
      * @return the Stroke assigned to the id
      */
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
new file mode 100644
index 0000000..299d0e3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionClassifier.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier which looks at the general direction of a stroke and evaluates it depending on
+ * the type of action that takes place.
+ */
+public class DirectionClassifier extends StrokeClassifier {
+    public DirectionClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        Point firstPoint = stroke.getPoints().get(0);
+        Point lastPoint = stroke.getPoints().get(stroke.getPoints().size() - 1);
+        return DirectionEvaluator.evaluate(lastPoint.x - firstPoint.x, lastPoint.y - firstPoint.y,
+                type);
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
new file mode 100644
index 0000000..e20b1ca6
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DirectionEvaluator.java
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class DirectionEvaluator {
+    public static float evaluate(float xDiff, float yDiff, int type) {
+        float falsingEvaluation = 5.5f;
+        boolean vertical = Math.abs(yDiff) >= Math.abs(xDiff);
+        switch (type) {
+            case Classifier.QUICK_SETTINGS:
+            case Classifier.NOTIFICATION_DRAG_DOWN:
+                if (!vertical || yDiff <= 0.0) {
+                    return falsingEvaluation;
+                }
+                break;
+            case Classifier.NOTIFICATION_DISMISS:
+                if (vertical) {
+                    return falsingEvaluation;
+                }
+                break;
+            case Classifier.UNLOCK:
+                if (!vertical || yDiff >= 0.0) {
+                    return falsingEvaluation;
+                }
+                break;
+            case Classifier.LEFT_AFFORDANCE:
+                if (xDiff < 0.0 && yDiff > 0.0) {
+                    return falsingEvaluation;
+                }
+                break;
+            case Classifier.RIGHT_AFFORDANCE:
+                if (xDiff > 0.0 && yDiff > 0.0) {
+                    return falsingEvaluation;
+                }
+            default:
+                break;
+        }
+        return 0.0f;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
new file mode 100644
index 0000000..8acb009
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DistanceRatioEvaluator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class DistanceRatioEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value <= 1.0) evaluation++;
+        if (value <= 0.5) evaluation++;
+        if (value > 4.0) evaluation++;
+        if (value > 7.0) evaluation++;
+        if (value > 14.0) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
new file mode 100644
index 0000000..8924694
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountClassifier.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier which looks at the ratio between the duration of the stroke and its number of
+ * points.
+ */
+public class DurationCountClassifier extends StrokeClassifier {
+    public DurationCountClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return DurationCountEvaluator.evaluate(stroke.getDurationSeconds() / stroke.getCount());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java
new file mode 100644
index 0000000..5395983
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/DurationCountEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+
+public class DurationCountEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.0105) evaluation++;
+        if (value < 0.00909) evaluation++;
+        if (value < 0.00667) evaluation++;
+        if (value > 0.0333) evaluation++;
+        if (value > 0.0500) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
new file mode 100644
index 0000000..78bc0dd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthClassifier.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier which looks at the distance between the first and the last point from the stroke.
+ */
+public class EndPointLengthClassifier extends StrokeClassifier {
+    public EndPointLengthClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return EndPointLengthEvaluator.evaluate(stroke.getEndPointLength());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java
new file mode 100644
index 0000000..bb2f1c4
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointLengthEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class EndPointLengthEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.05) evaluation += 2.0;
+        if (value < 0.1) evaluation += 2.0;
+        if (value < 0.2) evaluation += 2.0;
+        if (value < 0.3) evaluation += 2.0;
+        if (value < 0.4) evaluation += 2.0;
+        if (value < 0.5) evaluation += 2.0;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
new file mode 100644
index 0000000..c125e00
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioClassifier.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier which looks at the ratio between the total length covered by the stroke and the
+ * distance between the first and last point from this stroke.
+ */
+public class EndPointRatioClassifier extends StrokeClassifier {
+    public EndPointRatioClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        if (stroke.getTotalLength() == 0.0f) {
+            return 1.0f;
+        }
+        return EndPointRatioEvaluator.evaluate(
+                stroke.getEndPointLength() / stroke.getTotalLength());
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java
new file mode 100644
index 0000000..529fcec
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/EndPointRatioEvaluator.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class EndPointRatioEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.85) evaluation++;
+        if (value < 0.75) evaluation++;
+        if (value < 0.65) evaluation++;
+        if (value < 0.55) evaluation++;
+        if (value < 0.45) evaluation++;
+        if (value < 0.35) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
index 347273a..735a7c4 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/FalsingManager.java
@@ -39,7 +39,11 @@
 public class FalsingManager implements SensorEventListener {
     private static final String ENFORCE_BOUNCER = "falsing_manager_enforce_bouncer";
 
-    private static final int[] SENSORS = new int[] {
+    private static final int[] CLASSIFIER_SENSORS = new int[] {
+            Sensor.TYPE_PROXIMITY,
+    };
+
+    private static final int[] COLLECTOR_SENSORS = new int[] {
             Sensor.TYPE_ACCELEROMETER,
             Sensor.TYPE_GYROSCOPE,
             Sensor.TYPE_PROXIMITY,
@@ -113,7 +117,17 @@
     private void onSessionStart() {
         mBouncerOn = false;
         mSessionActive = true;
-        for (int sensorType : SENSORS) {
+
+        if (mHumanInteractionClassifier.isEnabled()) {
+            registerSensors(CLASSIFIER_SENSORS);
+        }
+        if (mDataCollector.isEnabled()) {
+            registerSensors(COLLECTOR_SENSORS);
+        }
+    }
+
+    private void registerSensors(int [] sensors) {
+        for (int sensorType : sensors) {
             Sensor s = mSensorManager.getDefaultSensor(sensorType);
             if (s != null) {
                 mSensorManager.registerListener(this, s, SensorManager.SENSOR_DELAY_GAME);
@@ -121,16 +135,19 @@
         }
     }
 
+    public boolean isClassiferEnabled() {
+        return mHumanInteractionClassifier.isEnabled();
+    }
+
     private boolean isEnabled() {
         return mHumanInteractionClassifier.isEnabled() || mDataCollector.isEnabled();
     }
 
     /**
-     * @param type the type of action for which this method is called
      * @return true if the classifier determined that this is not a human interacting with the phone
      */
-    public boolean isFalseTouch(int type) {
-        return mHumanInteractionClassifier.getFalseTouchEvaluation(type) > 0.5;
+    public boolean isFalseTouch() {
+        return mHumanInteractionClassifier.isFalseTouch();
     }
 
     @Override
@@ -189,6 +206,7 @@
     }
 
     public void onQsDown() {
+        mHumanInteractionClassifier.setType(Classifier.QUICK_SETTINGS);
         mDataCollector.onQsDown();
     }
 
@@ -197,6 +215,7 @@
     }
 
     public void onTrackingStarted() {
+        mHumanInteractionClassifier.setType(Classifier.UNLOCK);
         mDataCollector.onTrackingStarted();
     }
 
@@ -217,6 +236,7 @@
     }
 
     public void onNotificatonStartDraggingDown() {
+        mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DRAG_DOWN);
         mDataCollector.onNotificatonStartDraggingDown();
     }
 
@@ -229,6 +249,7 @@
     }
 
     public void onNotificatonStartDismissing() {
+        mHumanInteractionClassifier.setType(Classifier.NOTIFICATION_DISMISS);
         mDataCollector.onNotificatonStartDismissing();
     }
 
@@ -245,6 +266,11 @@
     }
 
     public void onAffordanceSwipingStarted(boolean rightCorner) {
+        if (rightCorner) {
+            mHumanInteractionClassifier.setType(Classifier.RIGHT_AFFORDANCE);
+        } else {
+            mHumanInteractionClassifier.setType(Classifier.LEFT_AFFORDANCE);
+        }
         mDataCollector.onAffordanceSwipingStarted(rightCorner);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
new file mode 100644
index 0000000..11388fc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/GestureClassifier.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * An abstract class for classifiers which classify the whole gesture (all the strokes which
+ * occurred from DOWN event to UP/CANCEL event)
+ */
+public abstract class GestureClassifier extends Classifier {
+
+    /**
+     * @param type the type of action for which this method is called
+     * @return a non-negative value which is used to determine whether the most recent gesture is a
+     *         false interaction; the bigger the value the greater the chance that this a false
+     *         interaction.
+     */
+    public abstract float getFalseTouchEvaluation(int type);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
new file mode 100644
index 0000000..85a9bee
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HistoryEvaluator.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+import java.util.ArrayList;
+
+/**
+ * Holds the evaluations for ended strokes and gestures. These values are decreased through time.
+ */
+public class HistoryEvaluator {
+    private static final float INTERVAL = 50.0f;
+    private static final float HISTORY_FACTOR = 0.9f;
+    private static final float EPSILON = 1e-5f;
+
+    private final ArrayList<Data> mStrokes = new ArrayList<>();
+    private final ArrayList<Data> mGestureWeights = new ArrayList<>();
+    private long mLastUpdate;
+
+    public HistoryEvaluator() {
+        mLastUpdate = System.currentTimeMillis();
+    }
+
+    public void addStroke(float evaluation) {
+        decayValue();
+        mStrokes.add(new Data(evaluation));
+    }
+
+    public void addGesture(float evaluation) {
+        decayValue();
+        mGestureWeights.add(new Data(evaluation));
+    }
+
+    /**
+     * Calculates the weighted average of strokes and adds to it the weighted average of gestures
+     */
+    public float getEvaluation() {
+        return weightedAverage(mStrokes) + weightedAverage(mGestureWeights);
+    }
+
+    private float weightedAverage(ArrayList<Data> list) {
+        float sumValue = 0.0f;
+        float sumWeight = 0.0f;
+        int size = list.size();
+        for (int i = 0; i < size; i++) {
+            Data data = list.get(i);
+            sumValue += data.evaluation * data.weight;
+            sumWeight += data.weight;
+        }
+
+        if (sumWeight == 0.0f) {
+            return 0.0f;
+        }
+
+        return sumValue / sumWeight;
+    }
+
+    private void decayValue() {
+        long currentTimeMillis = System.currentTimeMillis();
+
+        // All weights are multiplied by HISTORY_FACTOR after each INTERVAL milliseconds.
+        float factor = (float) Math.pow(HISTORY_FACTOR,
+                (float) (currentTimeMillis - mLastUpdate) / INTERVAL);
+
+        decayValue(mStrokes, factor);
+        decayValue(mGestureWeights, factor);
+        mLastUpdate = currentTimeMillis;
+    }
+
+    private void decayValue(ArrayList<Data> list, float factor) {
+        int size = list.size();
+        for (int i = 0; i < size; i++) {
+            list.get(i).weight *= factor;
+        }
+
+        // Removing evaluations with such small weights that they do not matter anymore
+        while (!list.isEmpty() && isZero(list.get(0).weight)) {
+            list.remove(0);
+        }
+    }
+
+    private boolean isZero(float x) {
+        return x <= EPSILON && x >= -EPSILON;
+    }
+
+    /**
+     * For each stroke it holds its initial value and the current weight. Initially the
+     * weight is set to 1.0
+     */
+    private static class Data {
+        public float evaluation;
+        public float weight;
+
+        public Data(float evaluation) {
+            this.evaluation = evaluation;
+            weight = 1.0f;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index a5f6df85..a7a5694 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -23,20 +23,33 @@
 import android.os.Handler;
 import android.os.UserHandle;
 import android.provider.Settings;
+import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+
 /**
  * An classifier trying to determine whether it is a human interacting with the phone or not.
  */
 public class HumanInteractionClassifier extends Classifier {
     private static final String HIC_ENABLE = "HIC_enable";
+    private static final float FINGER_DISTANCE = 0.1f;
     private static HumanInteractionClassifier sInstance = null;
 
     private final Handler mHandler = new Handler();
     private final Context mContext;
 
-    private AnglesVarianceClassifier mAnglesVarianceClassifier;
-    private boolean mEnableClassifier = false;
+    private ArrayList<StrokeClassifier> mStrokeClassifiers = new ArrayList<>();
+    private ArrayList<GestureClassifier> mGestureClassifiers = new ArrayList<>();
+    private ArrayDeque<MotionEvent> mBufferedEvents = new ArrayDeque<>();
+    private final int mStrokeClassifiersSize;
+    private final int mGestureClassifiersSize;
+    private final float mDpi;
+
+    private HistoryEvaluator mHistoryEvaluator;
+    private boolean mEnableClassifier = true;
+    private int mCurrentType = Classifier.GENERIC;
 
     protected final ContentObserver mSettingsObserver = new ContentObserver(mHandler) {
         @Override
@@ -47,8 +60,30 @@
 
     private HumanInteractionClassifier(Context context) {
         mContext = context;
-        mClassifierData = new ClassifierData();
-        mAnglesVarianceClassifier = new AnglesVarianceClassifier(mClassifierData);
+        DisplayMetrics displayMetrics = mContext.getResources().getDisplayMetrics();
+
+        // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
+        // were to be used separately. Due negligible differences in xdpi and ydpi we can just
+        // take the average.
+        mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
+        mClassifierData = new ClassifierData(mDpi);
+        mHistoryEvaluator = new HistoryEvaluator();
+
+        mStrokeClassifiers.add(new AnglesClassifier(mClassifierData));
+        mStrokeClassifiers.add(new SpeedClassifier(mClassifierData));
+        mStrokeClassifiers.add(new DurationCountClassifier(mClassifierData));
+        mStrokeClassifiers.add(new EndPointRatioClassifier(mClassifierData));
+        mStrokeClassifiers.add(new EndPointLengthClassifier(mClassifierData));
+        mStrokeClassifiers.add(new AccelerationClassifier(mClassifierData));
+        mStrokeClassifiers.add(new SpeedAnglesClassifier(mClassifierData));
+        mStrokeClassifiers.add(new LengthCountClassifier(mClassifierData));
+        mStrokeClassifiers.add(new DirectionClassifier(mClassifierData));
+
+        mGestureClassifiers.add(new PointerCountClassifier(mClassifierData));
+        mGestureClassifiers.add(new ProximityClassifier(mClassifierData));
+
+        mStrokeClassifiersSize = mStrokeClassifiers.size();
+        mGestureClassifiersSize = mGestureClassifiers.size();
 
         mContext.getContentResolver().registerContentObserver(
                 Settings.Global.getUriFor(HIC_ENABLE), false,
@@ -71,25 +106,95 @@
                 HIC_ENABLE, 0);
     }
 
+    public void setType(int type) {
+        mCurrentType = type;
+    }
+
     @Override
     public void onTouchEvent(MotionEvent event) {
-        if (mEnableClassifier) {
-            mClassifierData.update(event);
-            mAnglesVarianceClassifier.onTouchEvent(event);
-            mClassifierData.cleanUp(event);
+        if (!mEnableClassifier) {
+            return;
         }
+
+        // If the user is dragging down the notification, he might want to drag it down
+        // enough to see the content, read it for a while and then lift the finger to open
+        // the notification. This kind of motion scores very bad in the Classifier so the
+        // MotionEvents which are close to the current position of the finger are not
+        // sent to the classifiers until the finger moves far enough. When the finger if lifted
+        // up, the last MotionEvent which was far enough from the finger is set as the final
+        // MotionEvent and sent to the Classifiers.
+        if (mCurrentType == Classifier.NOTIFICATION_DRAG_DOWN) {
+            mBufferedEvents.add(MotionEvent.obtain(event));
+            Point pointEnd = new Point(event.getX() / mDpi, event.getY() / mDpi);
+
+            while (pointEnd.dist(new Point(mBufferedEvents.getFirst().getX() / mDpi,
+                    mBufferedEvents.getFirst().getY() / mDpi)) > FINGER_DISTANCE) {
+                addTouchEvent(mBufferedEvents.getFirst());
+                mBufferedEvents.remove();
+            }
+
+            int action = event.getActionMasked();
+            if (action == MotionEvent.ACTION_UP) {
+                mBufferedEvents.getFirst().setAction(MotionEvent.ACTION_UP);
+                addTouchEvent(mBufferedEvents.getFirst());
+                mBufferedEvents.clear();
+            }
+        } else {
+            addTouchEvent(event);
+        }
+    }
+
+    private void addTouchEvent(MotionEvent event) {
+        mClassifierData.update(event);
+
+        for (int i = 0; i < mStrokeClassifiersSize; i++) {
+            mStrokeClassifiers.get(i).onTouchEvent(event);
+        }
+
+        for (int i = 0; i < mGestureClassifiersSize; i++) {
+            mGestureClassifiers.get(i).onTouchEvent(event);
+        }
+
+        int size = mClassifierData.getEndingStrokes().size();
+        for (int i = 0; i < size; i++) {
+            Stroke stroke = mClassifierData.getEndingStrokes().get(i);
+            float evaluation = 0.0f;
+            for (int j = 0; j < mStrokeClassifiersSize; j++) {
+                evaluation += mStrokeClassifiers.get(j).getFalseTouchEvaluation(
+                        mCurrentType, stroke);
+            }
+            mHistoryEvaluator.addStroke(evaluation);
+        }
+
+        int action = event.getActionMasked();
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            float evaluation = 0.0f;
+            for (int i = 0; i < mGestureClassifiersSize; i++) {
+                evaluation += mGestureClassifiers.get(i).getFalseTouchEvaluation(mCurrentType);
+            }
+            mHistoryEvaluator.addGesture(evaluation);
+            setType(Classifier.GENERIC);
+        }
+
+        mClassifierData.cleanUp(event);
     }
 
     @Override
     public void onSensorChanged(SensorEvent event) {
+        for (int i = 0; i < mStrokeClassifiers.size(); i++) {
+            mStrokeClassifiers.get(i).onSensorChanged(event);
+        }
+
+        for (int i = 0; i < mGestureClassifiers.size(); i++) {
+            mGestureClassifiers.get(i).onSensorChanged(event);
+        }
     }
 
-    @Override
-    public float getFalseTouchEvaluation(int type) {
+    public boolean isFalseTouch() {
         if (mEnableClassifier) {
-            return mAnglesVarianceClassifier.getFalseTouchEvaluation(type);
+            return mHistoryEvaluator.getEvaluation() >= 5.0f;
         }
-        return 0.0f;
+        return false;
     }
 
     public boolean isEnabled() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
new file mode 100644
index 0000000..cedf467
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountClassifier.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier which looks at the ratio between the length of the stroke and its number of
+ * points. The number of points is subtracted by 2 because the UP event comes in with some delay
+ * and it should not influence the ratio and also strokes which are long and have a small number
+ * of points are punished more (these kind of strokes are usually bad ones and they tend to score
+ * well in other classifiers).
+ */
+public class LengthCountClassifier extends StrokeClassifier {
+    public LengthCountClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        return LengthCountEvaluator.evaluate(stroke.getTotalLength()
+                / Math.max(1.0f, stroke.getCount() - 2));
+    }
+}
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
new file mode 100644
index 0000000..dac7a6f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/LengthCountEvaluator.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier which looks at the ratio between the length of the stroke and its number of
+ * points.
+ */
+public class LengthCountEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 0.09) evaluation++;
+        if (value < 0.05) evaluation++;
+        if (value < 0.02) evaluation++;
+        if (value > 0.6) evaluation++;
+        if (value > 0.9) evaluation++;
+        if (value > 1.2) evaluation++;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Point.java b/packages/SystemUI/src/com/android/systemui/classifier/Point.java
index e7dbae1..f3dc2be 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Point.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Point.java
@@ -56,4 +56,28 @@
     public float dotProduct(Point a, Point b) {
         return (a.x - x) * (b.x - x) + (a.y - y) * (b.y - y);
     }
+
+    /**
+     * Calculates the angle in radians created by points (a, this, b). If any two of these points
+     * are the same, the method will return 0.0f
+     *
+     * @return the angle in radians
+     */
+    public float getAngle(Point a, Point b) {
+        float dist1 = dist(a);
+        float dist2 = dist(b);
+
+        if (dist1 == 0.0f || dist2 == 0.0f) {
+            return 0.0f;
+        }
+
+        float crossProduct = crossProduct(a, b);
+        float dotProduct = dotProduct(a, b);
+        float cos = Math.min(1.0f, Math.max(-1.0f, dotProduct / dist1 / dist2));
+        float angle = (float) Math.acos(cos);
+        if (crossProduct < 0.0) {
+            angle = 2.0f * (float) Math.PI - angle;
+        }
+        return angle;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
new file mode 100644
index 0000000..5097b63
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountClassifier.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+import android.view.MotionEvent;
+
+/**
+ * A classifier which looks at the total number of traces in the whole gesture.
+ */
+public class PointerCountClassifier extends GestureClassifier {
+    private int mCount;
+
+    public PointerCountClassifier(ClassifierData classifierData) {
+        mCount = 0;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mCount = 1;
+        }
+
+        if (action == MotionEvent.ACTION_POINTER_DOWN) {
+            ++mCount;
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type) {
+        return PointerCountEvaluator.evaluate(mCount);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
similarity index 73%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
index c47d194..d7a3af0 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/PointerCountEvaluator.java
@@ -11,11 +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.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class PointerCountEvaluator {
+    public static float evaluate(int value) {
+        return (value - 1) * (value - 1);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
new file mode 100644
index 0000000..6995064
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityClassifier.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+import android.hardware.Sensor;
+import android.hardware.SensorEvent;
+import android.view.MotionEvent;
+
+/**
+ * A classifier which looks at the proximity sensor during the gesture. It calculates the percentage
+ * the proximity sensor showing the near state during the whole gesture
+ */
+public class ProximityClassifier extends GestureClassifier {
+    private long mGestureStartTimeNano;
+    private long mNearStartTimeNano;
+    private long mNearDuration;
+    private boolean mNear;
+    private float mAverageNear;
+
+    public ProximityClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public void onSensorChanged(SensorEvent event) {
+        if (event.sensor.getType() == Sensor.TYPE_PROXIMITY) {
+            update(event.values[0] < event.sensor.getMaximumRange(), event.timestamp);
+        }
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mGestureStartTimeNano = event.getEventTimeNano();
+            mNearStartTimeNano = event.getEventTimeNano();
+            mNearDuration = 0;
+        }
+
+        if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+            update(mNear, event.getEventTimeNano());
+            long duration = event.getEventTimeNano() - mGestureStartTimeNano;
+
+            if (duration == 0) {
+                mAverageNear = mNear ? 1.0f : 0.0f;
+            } else {
+                mAverageNear = (float) mNearDuration / (float) duration;
+            }
+        }
+    }
+
+
+    /**
+     * @param near is the sensor showing the near state right now
+     * @param timestampNano time of this event in nanoseconds
+     */
+    private void update(boolean near, long timestampNano) {
+        // This if is necessary because MotionEvents and SensorEvents do not come in
+        // chronological order
+        if (timestampNano > mNearStartTimeNano) {
+            // if the state before was near then add the difference of the current time and
+            // mNearStartTimeNano to mNearDuration.
+            if (mNear) {
+                mNearDuration += timestampNano - mNearStartTimeNano;
+            }
+
+            // if the new state is near, set mNearStartTimeNano equal to this moment.
+            if (near) {
+                mNearStartTimeNano = timestampNano;
+            }
+        }
+        mNear = near;
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type) {
+        return ProximityEvaluator.evaluate(mAverageNear, type);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java
new file mode 100644
index 0000000..91002bf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/ProximityEvaluator.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class ProximityEvaluator {
+    public static float evaluate(float value, int type) {
+        float evaluation = 0.0f;
+        float threshold = 0.1f;
+        if (type == Classifier.QUICK_SETTINGS) {
+            threshold = 1.0f;
+        }
+        if (value >= threshold) evaluation += 2.0;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
new file mode 100644
index 0000000..d544a3d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesClassifier.java
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+import android.view.MotionEvent;
+
+import java.lang.Math;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+
+/**
+ * A classifier which for each point from a stroke, it creates a point on plane with coordinates
+ * (timeOffsetNano, distanceCoveredUpToThisPoint) (scaled by DURATION_SCALE and LENGTH_SCALE)
+ * and then it calculates the angle variance of these points like the class
+ * {@link AnglesClassifier} (without splitting it into two parts). The classifier ignores
+ * the last point of a stroke because the UP event comes in with some delay and this ruins the
+ * smoothness of this curve. Additionally, the classifier classifies calculates the percentage of
+ * angles which value is in [PI - ANGLE_DEVIATION, 2* PI) interval. The reason why the classifier
+ * does that is because the speed of a good stroke is most often increases, so most of these angels
+ * should be in this interval.
+ */
+public class SpeedAnglesClassifier extends StrokeClassifier {
+    private HashMap<Stroke, Data> mStrokeMap = new HashMap<>();
+
+    public SpeedAnglesClassifier(ClassifierData classifierData) {
+        mClassifierData = classifierData;
+    }
+
+    @Override
+    public void onTouchEvent(MotionEvent event) {
+        int action = event.getActionMasked();
+
+        if (action == MotionEvent.ACTION_DOWN) {
+            mStrokeMap.clear();
+        }
+
+        for (int i = 0; i < event.getPointerCount(); i++) {
+            Stroke stroke = mClassifierData.getStroke(event.getPointerId(i));
+
+            if (mStrokeMap.get(stroke) == null) {
+                mStrokeMap.put(stroke, new Data());
+            }
+
+            if (action != MotionEvent.ACTION_UP && action != MotionEvent.ACTION_CANCEL
+                    && !(action == MotionEvent.ACTION_POINTER_UP && i == event.getActionIndex())) {
+                mStrokeMap.get(stroke).addPoint(
+                        stroke.getPoints().get(stroke.getPoints().size() - 1));
+            }
+        }
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        Data data = mStrokeMap.get(stroke);
+        return SpeedVarianceEvaluator.evaluate(data.getAnglesVariance())
+                + SpeedAnglesPercentageEvaluator.evaluate(data.getAnglesPercentage());
+    }
+
+    private static class Data {
+        private final float DURATION_SCALE = 1e8f;
+        private final float LENGTH_SCALE = 1.0f;
+        private final float ANGLE_DEVIATION = (float) Math.PI / 10.0f;
+
+        private List<Point> mLastThreePoints = new ArrayList<>();
+        private Point mPreviousPoint;
+        private float mPreviousAngle;
+        private float mSumSquares;
+        private float mSum;
+        private float mCount;
+        private float mDist;
+        private float mAnglesCount;
+        private float mAcceleratingAngles;
+
+        public Data() {
+            mPreviousPoint = null;
+            mPreviousAngle = (float) Math.PI;
+            mSumSquares = 0.0f;
+            mSum = 0.0f;
+            mCount = 1.0f;
+            mDist = 0.0f;
+            mAnglesCount = mAcceleratingAngles = 0.0f;
+        }
+
+        public void addPoint(Point point) {
+            if (mPreviousPoint != null) {
+                mDist += mPreviousPoint.dist(point);
+            }
+
+            mPreviousPoint = point;
+            Point speedPoint = new Point((float) point.timeOffsetNano / DURATION_SCALE,
+                    mDist / LENGTH_SCALE);
+
+            // Checking if the added point is different than the previously added point
+            // Repetitions are being ignored so that proper angles are calculated.
+            if (mLastThreePoints.isEmpty()
+                    || !mLastThreePoints.get(mLastThreePoints.size() - 1).equals(speedPoint)) {
+                mLastThreePoints.add(speedPoint);
+                if (mLastThreePoints.size() == 4) {
+                    mLastThreePoints.remove(0);
+
+                    float angle = mLastThreePoints.get(1).getAngle(mLastThreePoints.get(0),
+                            mLastThreePoints.get(2));
+
+                    mAnglesCount++;
+                    if (angle >= (float) Math.PI - ANGLE_DEVIATION) {
+                        mAcceleratingAngles++;
+                    }
+
+                    float difference = angle - mPreviousAngle;
+                    mSum += difference;
+                    mSumSquares += difference * difference;
+                    mCount += 1.0;
+                    mPreviousAngle = angle;
+                }
+            }
+        }
+
+        public float getAnglesVariance() {
+            return mSumSquares / mCount - (mSum / mCount) * (mSum / mCount);
+        }
+
+        public float getAnglesPercentage() {
+            if (mAnglesCount == 0.0f) {
+                return 1.0f;
+            }
+            return (mAcceleratingAngles) / mAnglesCount;
+        }
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java
similarity index 61%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java
index c47d194..2a45fa3 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedAnglesPercentageEvaluator.java
@@ -11,11 +11,17 @@
  * 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.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class SpeedAnglesPercentageEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 1.00) evaluation++;
+        if (value < 0.95) evaluation++;
+        if (value < 0.90) evaluation++;
+        return evaluation;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
new file mode 100644
index 0000000..81b78c7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedClassifier.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * A classifier that looks at the speed of the stroke. It calculates the speed of a stroke in
+ * inches per second.
+ */
+public class SpeedClassifier extends StrokeClassifier {
+    private final float NANOS_TO_SECONDS = 1e9f;
+
+    public SpeedClassifier(ClassifierData classifierData) {
+    }
+
+    @Override
+    public float getFalseTouchEvaluation(int type, Stroke stroke) {
+        float duration = (float) stroke.getDurationNanos() / NANOS_TO_SECONDS;
+        if (duration == 0.0f) {
+            return SpeedEvaluator.evaluate(0.0f);
+        }
+        return SpeedEvaluator.evaluate(stroke.getTotalLength() / duration);
+    }
+}
\ No newline at end of file
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
similarity index 61%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
index c47d194..c0e4a2d 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedEvaluator.java
@@ -11,11 +11,17 @@
  * 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.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class SpeedEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value < 4.0 || value > 35.0) evaluation += 1.0;
+        if (value < 2.2) evaluation += 1.0;
+        if (value > 50.0) evaluation += 1.0;
+        return evaluation;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
similarity index 65%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
index c47d194..349aa9e 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedRatioEvaluator.java
@@ -11,11 +11,16 @@
  * 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.server.devicepolicy;
 
-import android.app.admin.DeviceAdminReceiver;
+package com.android.systemui.classifier;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class SpeedRatioEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value > 9.0) ++evaluation;
+        if (value > 18.0) ++evaluation;
+        return evaluation;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java
new file mode 100644
index 0000000..8f9a7e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/SpeedVarianceEvaluator.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+public class SpeedVarianceEvaluator {
+    public static float evaluate(float value) {
+        float evaluation = 0.0f;
+        if (value > 0.06) evaluation += 1.0;
+        if (value > 0.15) evaluation += 1.0;
+        if (value > 0.3) evaluation += 1.0;
+        if (value > 0.6) evaluation += 1.0;
+        return evaluation;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
index f386cbe4..fb04d3e 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/Stroke.java
@@ -19,20 +19,50 @@
 import java.util.ArrayList;
 
 /**
- * Contains data about movement traces (pointers)
+ * Contains data about a stroke (a single trace, all the events from a given id from the
+ * DOWN/POINTER_DOWN event till the UP/POINTER_UP/CANCEL event.)
  */
 public class Stroke {
+    private final float NANOS_TO_SECONDS = 1e9f;
+
     private ArrayList<Point> mPoints = new ArrayList<>();
     private long mStartTimeNano;
     private long mEndTimeNano;
+    private float mLength;
+    private final float mDpi;
 
-    public Stroke(long eventTimeNano) {
+    public Stroke(long eventTimeNano, float dpi) {
+        mDpi = dpi;
         mStartTimeNano = mEndTimeNano = eventTimeNano;
     }
 
     public void addPoint(float x, float y, long eventTimeNano) {
         mEndTimeNano = eventTimeNano;
-        mPoints.add(new Point(x, y, eventTimeNano - mStartTimeNano));
+        Point point = new Point(x / mDpi, y / mDpi, eventTimeNano - mStartTimeNano);
+        if (!mPoints.isEmpty()) {
+            mLength += mPoints.get(mPoints.size() - 1).dist(point);
+        }
+        mPoints.add(point);
+    }
+
+    public int getCount() {
+        return mPoints.size();
+    }
+
+    public float getTotalLength() {
+        return mLength;
+    }
+
+    public float getEndPointLength() {
+        return mPoints.get(0).dist(mPoints.get(mPoints.size() - 1));
+    }
+
+    public long getDurationNanos() {
+        return mEndTimeNano - mStartTimeNano;
+    }
+
+    public float getDurationSeconds() {
+        return (float) getDurationNanos() / NANOS_TO_SECONDS;
     }
 
     public ArrayList<Point> getPoints() {
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java
new file mode 100644
index 0000000..5da392f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/classifier/StrokeClassifier.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2015 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.classifier;
+
+/**
+ * An abstract class for classifiers which classify each stroke separately.
+ */
+public abstract class StrokeClassifier extends Classifier {
+
+    /**
+     * @param type the type of action for which this method is called
+     * @param stroke the stroke for which the evaluation will be calculated
+     * @return a non-negative value which is used to determine whether this a false touch; the
+     *         bigger the value the greater the chance that this a false touch
+     */
+    public abstract float getFalseTouchEvaluation(int type, Stroke stroke);
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 3b3593b..e562682 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -30,16 +30,7 @@
 import android.view.ViewGroup;
 
 import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.Listenable;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.statusbar.policy.*;
 
 import java.util.Collection;
 import java.util.Objects;
@@ -349,6 +340,9 @@
         CastController getCastController();
         FlashlightController getFlashlightController();
         KeyguardMonitor getKeyguardMonitor();
+        UserSwitcherController getUserSwitcherController();
+        UserInfoController getUserInfoController();
+        BatteryController getBatteryController();
 
         public interface Callback {
             void onTilesChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
index 08cdc1e..e575923 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTileView.java
@@ -267,7 +267,7 @@
         final int w = MeasureSpec.getSize(widthMeasureSpec);
         final int h = MeasureSpec.getSize(heightMeasureSpec);
         final int iconSpec = exactly(mIconSizePx);
-        mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.AT_MOST), iconSpec);
+        mIcon.measure(MeasureSpec.makeMeasureSpec(w, MeasureSpec.EXACTLY), iconSpec);
         switch (mType) {
             case QS_TYPE_QUICK:
                 mCircle.measure(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
index 84b05d0..f676ea3 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSTileHost.java
@@ -44,7 +44,8 @@
                 host.getRotationLockController(), host.getNetworkController(),
                 host.getZenModeController(), host.getHotspotController(), host.getCastController(),
                 host.getFlashlightController(), host.getUserSwitcherController(),
-                host.getKeyguardMonitor(), new BlankSecurityController());
+                host.getUserInfoController(), host.getKeyguardMonitor(),
+                new BlankSecurityController(), host.getBatteryController());
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
new file mode 100644
index 0000000..8f9655d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatteryTile.java
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2015 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.qs.tiles;
+
+import android.content.Context;
+import android.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.os.Handler;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.BatteryMeterDrawable;
+import com.android.systemui.R;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.BatteryController;
+
+import java.text.NumberFormat;
+
+public class BatteryTile extends QSTile<QSTile.State> implements BatteryController.BatteryStateChangeCallback {
+
+    private final BatteryMeterDrawable mDrawable;
+    private final BatteryController mBatteryController;
+
+    private int mLevel;
+
+    public BatteryTile(Host host) {
+        super(host);
+        mBatteryController = host.getBatteryController();
+        mDrawable = new BatteryMeterDrawable(host.getContext(), new Handler(),
+                host.getContext().getColor(R.color.batterymeter_frame_color));
+        mDrawable.setBatteryController(mBatteryController);
+    }
+
+    @Override
+    protected State newTileState() {
+        return new QSTile.State();
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsLogger.QS_BATTERY_TILE;
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mDrawable.startListening();
+            mBatteryController.addStateChangedCallback(this);
+        } else {
+            mDrawable.stopListening();
+            mBatteryController.removeStateChangedCallback(this);
+        }
+    }
+
+    @Override
+    protected void handleClick() {
+        mHost.startActivityDismissingKeyguard(new Intent(Intent.ACTION_POWER_USAGE_SUMMARY));
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        int level = (arg != null) ? (Integer) arg : mLevel;
+        String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
+
+        state.visible = true;
+        state.icon = new Icon() {
+            @Override
+            public Drawable getDrawable(Context context) {
+                return mDrawable;
+            }
+        };
+        state.label = percentage;
+    }
+
+    @Override
+    public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
+        mLevel = level;
+        refreshState((Integer) level);
+    }
+
+    @Override
+    public void onPowerSaveChanged() {
+
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
new file mode 100644
index 0000000..3675f02
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/QLockTile.java
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2015 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.qs.tiles;
+
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.QSTileView;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.R;
+
+public class QLockTile extends QSTile<QSTile.State> implements KeyguardMonitor.Callback {
+
+    private final KeyguardMonitor mKeyguard;
+
+    public QLockTile(Host host) {
+        super(host);
+        mKeyguard = host.getKeyguardMonitor();
+    }
+
+    @Override
+    public int getTileType() {
+        return QSTileView.QS_TYPE_QUICK;
+    }
+
+    @Override
+    protected State newTileState() {
+        return new State();
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mKeyguard.addCallback(this);
+        } else {
+            mKeyguard.removeCallback(this);
+        }
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsLogger.QS_LOCK_TILE;
+    }
+
+    @Override
+    public void onKeyguardChanged() {
+        refreshState();
+    }
+
+    @Override
+    protected void handleClick() {
+        if (mKeyguard.isShowing()) {
+            mKeyguard.unlock();
+        } else {
+            mKeyguard.lock();
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        // TOD: Content description.
+        state.visible = true;
+        if (mKeyguard.isShowing()) {
+            state.icon = ResourceIcon.get(R.drawable.ic_qs_lock);
+        } else {
+            state.icon = ResourceIcon.get(R.drawable.ic_qs_lock_open);
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
new file mode 100644
index 0000000..3c5ab8d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/UserTile.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2015 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.qs.tiles;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.Pair;
+import com.android.internal.logging.MetricsLogger;
+import com.android.systemui.qs.QSTile;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+
+public class UserTile extends QSTile<QSTile.State> implements UserInfoController.OnUserInfoChangedListener {
+
+    private final UserSwitcherController mUserSwitcherController;
+    private final UserInfoController mUserInfoController;
+    private Pair<String, Drawable> mLastUpdate;
+
+    public UserTile(Host host) {
+        super(host);
+        mUserSwitcherController = host.getUserSwitcherController();
+        mUserInfoController = host.getUserInfoController();
+    }
+
+    @Override
+    protected State newTileState() {
+        return new QSTile.State();
+    }
+
+    @Override
+    protected void handleClick() {
+        showDetail(true);
+    }
+
+    @Override
+    public DetailAdapter getDetailAdapter() {
+        return mUserSwitcherController.userDetailAdapter;
+    }
+
+    @Override
+    public int getMetricsCategory() {
+        return MetricsLogger.QS_USER_TILE;
+    }
+
+    @Override
+    public void setListening(boolean listening) {
+        if (listening) {
+            mUserInfoController.addListener(this);
+        } else {
+            mUserInfoController.remListener(this);
+        }
+    }
+
+    @Override
+    protected void handleUpdateState(State state, Object arg) {
+        final Pair<String, Drawable> p = arg != null ? (Pair<String, Drawable>) arg : mLastUpdate;
+        state.visible = p != null;
+        if (!state.visible) return;
+        state.label = p.first;
+        // TODO: Better content description.
+        state.contentDescription = p.first;
+        state.icon = new Icon() {
+            @Override
+            public Drawable getDrawable(Context context) {
+                return p.second;
+            }
+        };
+    }
+
+    @Override
+    public void onUserInfoChanged(String name, Drawable picture) {
+        mLastUpdate = new Pair<>(name, picture);
+        refreshState(mLastUpdate);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Constants.java b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
index e1a8815..9781664 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Constants.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Constants.java
@@ -29,8 +29,6 @@
     }
 
     public static class DebugFlags {
-        // Enable this with any other debug flag to see more info
-        public static final boolean Verbose = false;
 
         public static class App {
             // Enables debug drawing for the transition thumbnail
@@ -39,10 +37,6 @@
             public static final boolean EnableTaskFiltering = false;
             // Enables dismiss-all
             public static final boolean EnableDismissAll = false;
-            // Enables debug mode
-            public static final boolean EnableDebugMode = false;
-            // Enables the search bar layout
-            public static final boolean EnableSearchLayout = true;
             // Enables the thumbnail alpha on the front-most task
             public static final boolean EnableThumbnailAlphaOnFrontmost = false;
             // This disables the bitmap and icon caches
@@ -63,7 +57,6 @@
     public static class Values {
         public static class App {
             public static int AppWidgetHostId = 1024;
-            public static String DebugModeVersion = "A";
         }
 
         public static class TaskStackView {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index cbccaf8..23cc8f0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -38,7 +38,6 @@
 import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.View;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
@@ -164,7 +163,6 @@
     static RecentsTaskLoadPlan sInstanceLoadPlan;
     static Recents sInstance;
 
-    LayoutInflater mInflater;
     SystemServicesProxy mSystemServicesProxy;
     Handler mHandler;
     TaskStackListenerImpl mTaskStackListener;
@@ -176,12 +174,14 @@
 
     // Task launching
     RecentsConfiguration mConfig;
+    Rect mSearchBarBounds = new Rect();
     Rect mTaskStackBounds = new Rect();
-    Rect mSystemInsets = new Rect();
+    Rect mLastTaskViewBounds = new Rect();
     TaskViewTransform mTmpTransform = new TaskViewTransform();
     int mStatusBarHeight;
     int mNavBarHeight;
     int mNavBarWidth;
+    int mTaskBarHeight;
 
     // Header (for transition)
     TaskViewHeader mHeaderBar;
@@ -229,11 +229,11 @@
         if (sInstance == null) {
             sInstance = this;
         }
+        Resources res = mContext.getResources();
         RecentsTaskLoader.initialize(mContext);
-        mInflater = LayoutInflater.from(mContext);
+        LayoutInflater inflater = LayoutInflater.from(mContext);
         mSystemServicesProxy = new SystemServicesProxy(mContext);
         mHandler = new Handler();
-        mTaskStackBounds = new Rect();
         mAppWidgetHost = new RecentsAppWidgetHost(mContext, Constants.Values.App.AppWidgetHostId);
 
         // Register the task stack listener
@@ -241,7 +241,7 @@
         mSystemServicesProxy.registerTaskStackListener(mTaskStackListener);
 
         // Only the owner has the callback to update the SysUI visibility flags, so all non-owner
-        // instances of AlternateRecentsComponent needs to notify the owner when the visibility
+        // instances of RecentsComponent needs to notify the owner when the visibility
         // changes.
         if (mSystemServicesProxy.isForegroundUserSystem()) {
             mProxyBroadcastReceiver = new RecentsOwnerEventProxyReceiver();
@@ -254,8 +254,16 @@
 
         // Initialize some static datastructures
         TaskStackViewLayoutAlgorithm.initializeCurve();
-        // Load the header bar layout
-        reloadHeaderBarLayout();
+        // Initialize the static configuration resources
+        mConfig = RecentsConfiguration.initialize(mContext, mSystemServicesProxy);
+        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
+        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
+        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
+        mTaskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
+        mDummyStackView = new TaskStackView(mContext, new TaskStack());
+        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+                null, false);
+        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
 
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
@@ -273,6 +281,7 @@
     @Override
     public void onBootCompleted() {
         mBootCompleted = true;
+        reloadHeaderBarLayout(true /* tryAndBindSearchWidget */);
     }
 
     /** Shows the Recents. */
@@ -293,7 +302,7 @@
         mTriggeredFromAltTab = triggeredFromAltTab;
 
         try {
-            startRecentsActivity();
+            showRecentsActivity();
         } catch (ActivityNotFoundException e) {
             Console.logRawError("Failed to launch RecentAppsIntent", e);
         }
@@ -488,54 +497,52 @@
     void configurationChanged() {
         // Don't reuse task stack views if the configuration changes
         mCanReuseTaskStackViews = false;
-        // Reload the header bar layout
-        reloadHeaderBarLayout();
+        mConfig.updateOnConfigurationChange();
     }
 
-    /** Prepares the header bar layout. */
-    void reloadHeaderBarLayout() {
-        Resources res = mContext.getResources();
+    /**
+     * Prepares the header bar layout for the next transition, if the task view bounds has changed
+     * since the last call, it will attempt to re-measure and layout the header bar to the new size.
+     *
+     * @param tryAndBindSearchWidget if set, will attempt to fetch and bind the search widget if one
+     *                               is not already bound (can be expensive)
+     */
+    void reloadHeaderBarLayout(boolean tryAndBindSearchWidget) {
         Rect windowRect = mSystemServicesProxy.getWindowRect();
 
-        mStatusBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.status_bar_height);
-        mNavBarHeight = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_height);
-        mNavBarWidth = res.getDimensionPixelSize(com.android.internal.R.dimen.navigation_bar_width);
-        mConfig = RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
-        mConfig.updateOnConfigurationChange();
-        Rect searchBarBounds = new Rect();
-        // Try and pre-emptively bind the search widget on startup to ensure that we
-        // have the right thumbnail bounds to animate to.
-        // Note: We have to reload the widget id before we get the task stack bounds below
-        if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
-            mConfig.getSearchBarBounds(windowRect,
-                    mStatusBarHeight, searchBarBounds);
+        // Update the configuration for the current state
+        mConfig.update(mContext, mSystemServicesProxy, mSystemServicesProxy.getWindowRect());
+
+        if (tryAndBindSearchWidget) {
+            // Try and pre-emptively bind the search widget on startup to ensure that we
+            // have the right thumbnail bounds to animate to.
+            // Note: We have to reload the widget id before we get the task stack bounds below
+            if (mSystemServicesProxy.getOrBindSearchAppWidget(mContext, mAppWidgetHost) != null) {
+                mConfig.getSearchBarBounds(windowRect,
+                        mStatusBarHeight, mSearchBarBounds);
+            }
         }
         mConfig.getAvailableTaskStackBounds(windowRect,
-                mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0), searchBarBounds,
-                mTaskStackBounds);
-        if (mConfig.isLandscape && mConfig.hasTransposedNavBar) {
-            mSystemInsets.set(0, mStatusBarHeight, mNavBarWidth, 0);
-        } else {
-            mSystemInsets.set(0, mStatusBarHeight, 0, mNavBarHeight);
-        }
+                mStatusBarHeight, (mConfig.hasTransposedNavBar ? mNavBarWidth : 0),
+                mSearchBarBounds, mTaskStackBounds);
+        int systemBarBottomInset = mConfig.hasTransposedNavBar ? 0 : mNavBarHeight;
 
-        // Inflate the header bar layout so that we can rebind and draw it for the transition
-        TaskStack stack = new TaskStack();
-        mDummyStackView = new TaskStackView(mContext, stack);
+        // Rebind the header bar and draw it for the transition
         TaskStackViewLayoutAlgorithm algo = mDummyStackView.getStackAlgorithm();
         Rect taskStackBounds = new Rect(mTaskStackBounds);
-        taskStackBounds.bottom -= mSystemInsets.bottom;
+        taskStackBounds.bottom -= systemBarBottomInset;
         algo.computeRects(windowRect.width(), windowRect.height(), taskStackBounds);
-        Rect taskViewSize = algo.getUntransformedTaskViewSize();
-        int taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-        synchronized (mHeaderBarLock) {
-            mHeaderBar = (TaskViewHeader) mInflater.inflate(R.layout.recents_task_view_header, null,
-                    false);
-            mHeaderBar.measure(
-                    View.MeasureSpec.makeMeasureSpec(taskViewSize.width(), View.MeasureSpec.EXACTLY),
-                    View.MeasureSpec.makeMeasureSpec(taskBarHeight, View.MeasureSpec.EXACTLY));
-            // TODO: may not be needed
-            mHeaderBar.layout(0, 0, taskViewSize.width(), taskBarHeight);
+        Rect taskViewBounds = algo.getUntransformedTaskViewBounds();
+        if (!taskViewBounds.equals(mLastTaskViewBounds)) {
+            mLastTaskViewBounds.set(taskViewBounds);
+
+            int taskViewWidth = taskViewBounds.width();
+            synchronized (mHeaderBarLock) {
+                mHeaderBar.measure(
+                    View.MeasureSpec.makeMeasureSpec(taskViewWidth, View.MeasureSpec.EXACTLY),
+                    View.MeasureSpec.makeMeasureSpec(mTaskBarHeight, View.MeasureSpec.EXACTLY));
+                mHeaderBar.layout(0, 0, taskViewWidth, mTaskBarHeight);
+            }
         }
     }
 
@@ -560,17 +567,17 @@
             return;
         } else {
             // Otherwise, start the recents activity
-            startRecentsActivity(topTask, isTopTaskHome.value);
+            showRecentsActivity(topTask, isTopTaskHome.value);
         }
     }
 
-    /** Starts the recents activity if it is not already running */
-    void startRecentsActivity() {
+    /** Shows the recents activity if it is not already running */
+    void showRecentsActivity() {
         // Check if the top task is in the home stack, and start the recents activity
         ActivityManager.RunningTaskInfo topTask = mSystemServicesProxy.getTopMostTask();
         MutableBoolean isTopTaskHome = new MutableBoolean(true);
         if (topTask == null || !mSystemServicesProxy.isRecentsTopMost(topTask, isTopTaskHome)) {
-            startRecentsActivity(topTask, isTopTaskHome.value);
+            showRecentsActivity(topTask, isTopTaskHome.value);
         }
     }
 
@@ -732,30 +739,18 @@
         return mTmpTransform;
     }
 
-    /** Starts the recents activity */
-    void startRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
+    /** Shows the recents activity */
+    void showRecentsActivity(ActivityManager.RunningTaskInfo topTask, boolean isTopTaskHome) {
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
-        RecentsConfiguration.reinitialize(mContext, mSystemServicesProxy);
+
+        // Update the header bar if necessary
+        reloadHeaderBarLayout(false /* tryAndBindSearchWidget */);
 
         if (sInstanceLoadPlan == null) {
             // Create a new load plan if onPreloadRecents() was never triggered
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
         }
 
-        // Temporarily skip the transition (use a dummy fade) if multi stack is enabled.
-        // For multi-stack we need to figure out where each of the tasks are going.
-        if (mConfig.multiWindowEnabled) {
-            loader.preloadTasks(sInstanceLoadPlan, true);
-            TaskStack stack = sInstanceLoadPlan.getTaskStack();
-            mDummyStackView.updateMinMaxScrollForStack(stack, mTriggeredFromAltTab, true);
-            TaskStackViewLayoutAlgorithm.VisibilityReport stackVr =
-                    mDummyStackView.computeStackVisibilityReport();
-            ActivityOptions opts = getUnknownTransitionActivityOptions();
-            startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
-                    false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
-            return;
-        }
-
         if (!sInstanceLoadPlan.hasTasks()) {
             loader.preloadTasks(sInstanceLoadPlan, isTopTaskHome);
         }
@@ -774,7 +769,7 @@
             ActivityOptions opts = getThumbnailTransitionActivityOptions(topTask, stack,
                     mDummyStackView);
             if (opts != null) {
-                startAlternateRecentsActivity(topTask, opts, false /* fromHome */,
+                startRecentsActivity(topTask, opts, false /* fromHome */,
                         false /* fromSearchHome */, true /* fromThumbnail */, stackVr);
             } else {
                 // Fall through below to the non-thumbnail transition
@@ -794,12 +789,12 @@
                 boolean fromSearchHome = (homeActivityPackage != null) &&
                         homeActivityPackage.equals(searchWidgetPackage);
                 ActivityOptions opts = getHomeTransitionActivityOptions(fromSearchHome);
-                startAlternateRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
+                startRecentsActivity(topTask, opts, true /* fromHome */, fromSearchHome,
                         false /* fromThumbnail */, stackVr);
             } else {
                 // Otherwise we do the normal fade from an unknown source
                 ActivityOptions opts = getUnknownTransitionActivityOptions();
-                startAlternateRecentsActivity(topTask, opts, true /* fromHome */,
+                startRecentsActivity(topTask, opts, true /* fromHome */,
                         false /* fromSearchHome */, false /* fromThumbnail */, stackVr);
             }
         }
@@ -807,19 +802,20 @@
     }
 
     /** Starts the recents activity */
-    void startAlternateRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-            ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
-            TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
+    void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+              ActivityOptions opts, boolean fromHome, boolean fromSearchHome, boolean fromThumbnail,
+              TaskStackViewLayoutAlgorithm.VisibilityReport vr) {
         // Update the configuration based on the launch options
-        mConfig.launchedFromHome = fromSearchHome || fromHome;
-        mConfig.launchedFromSearchHome = fromSearchHome;
-        mConfig.launchedFromAppWithThumbnail = fromThumbnail;
-        mConfig.launchedToTaskId = (topTask != null) ? topTask.id : -1;
-        mConfig.launchedWithAltTab = mTriggeredFromAltTab;
-        mConfig.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
-        mConfig.launchedNumVisibleTasks = vr.numVisibleTasks;
-        mConfig.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
-        mConfig.launchedHasConfigurationChanged = false;
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        launchState.launchedFromHome = fromSearchHome || fromHome;
+        launchState.launchedFromSearchHome = fromSearchHome;
+        launchState.launchedFromAppWithThumbnail = fromThumbnail;
+        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        launchState.launchedWithAltTab = mTriggeredFromAltTab;
+        launchState.launchedReuseTaskStackViews = mCanReuseTaskStackViews;
+        launchState.launchedNumVisibleTasks = vr.numVisibleTasks;
+        launchState.launchedNumVisibleThumbnails = vr.numVisibleThumbnails;
+        launchState.launchedHasConfigurationChanged = false;
 
         Intent intent = new Intent(sToggleRecentsAction);
         intent.setClassName(sRecentsPackage, sRecentsActivity);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 4bb3e4a..9ce6b2c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -25,27 +25,21 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.res.Configuration;
 import android.os.Bundle;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.view.KeyEvent;
 import android.view.View;
 import android.view.ViewStub;
-import android.widget.Toast;
-
 import com.android.internal.logging.MetricsLogger;
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.Console;
-import com.android.systemui.recents.misc.DebugTrigger;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoadPlan;
 import com.android.systemui.recents.model.RecentsTaskLoader;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
-import com.android.systemui.recents.views.DebugOverlayView;
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.recents.views.ViewAnimation;
@@ -57,8 +51,7 @@
  * The main Recents activity that is started from AlternateRecentsComponent.
  */
 public class RecentsActivity extends Activity implements RecentsView.RecentsViewCallbacks,
-        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks,
-        DebugOverlayView.DebugOverlayViewCallbacks {
+        RecentsAppWidgetHost.RecentsAppWidgetHostCallbacks {
 
     RecentsConfiguration mConfig;
     long mLastTabKeyEventTime;
@@ -67,9 +60,7 @@
     RecentsView mRecentsView;
     SystemBarScrimViews mScrimViews;
     ViewStub mEmptyViewStub;
-    ViewStub mDebugOverlayStub;
     View mEmptyView;
-    DebugOverlayView mDebugOverlay;
 
     // Resize task debug
     RecentsResizeTaskDialog mResizeTaskDebugDialog;
@@ -176,16 +167,6 @@
         }
     };
 
-    /**
-     * A custom debug trigger to listen for a debug key chord.
-     */
-    final DebugTrigger mDebugTrigger = new DebugTrigger(new Runnable() {
-        @Override
-        public void run() {
-            onDebugModeTriggered();
-        }
-    });
-
     /** Updates the set of recent tasks */
     void updateRecentsTasks() {
         // If AlternateRecentsComponent has preloaded a load plan, then use that to prevent
@@ -197,18 +178,19 @@
         }
 
         // Start loading tasks according to the load plan
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         if (!plan.hasTasks()) {
-            loader.preloadTasks(plan, mConfig.launchedFromHome);
+            loader.preloadTasks(plan, launchState.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
-        loadOpts.runningTaskId = mConfig.launchedToTaskId;
-        loadOpts.numVisibleTasks = mConfig.launchedNumVisibleTasks;
-        loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
+        loadOpts.runningTaskId = launchState.launchedToTaskId;
+        loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
+        loadOpts.numVisibleTaskThumbnails = launchState.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
         TaskStack stack = plan.getTaskStack();
-        mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
-        if (!mConfig.launchedWithNoRecentTasks) {
+        launchState.launchedWithNoRecentTasks = !plan.hasTasks();
+        if (!launchState.launchedWithNoRecentTasks) {
             mRecentsView.setTaskStack(stack);
         }
 
@@ -219,19 +201,19 @@
                 Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent,
             ActivityOptions.makeCustomAnimation(this,
-                mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
+                    launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_enter :
                         R.anim.recents_to_launcher_enter,
-                    mConfig.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
+                    launchState.launchedFromSearchHome ? R.anim.recents_to_search_launcher_exit :
                         R.anim.recents_to_launcher_exit));
 
         // Mark the task that is the launch target
         int launchTaskIndexInStack = 0;
-        if (mConfig.launchedToTaskId != -1) {
+        if (launchState.launchedToTaskId != -1) {
             ArrayList<Task> tasks = stack.getTasks();
             int taskCount = tasks.size();
             for (int j = 0; j < taskCount; j++) {
                 Task t = tasks.get(j);
-                if (t.key.id == mConfig.launchedToTaskId) {
+                if (t.key.id == launchState.launchedToTaskId) {
                     t.isLaunchTarget = true;
                     launchTaskIndexInStack = tasks.size() - j - 1;
                     break;
@@ -240,7 +222,7 @@
         }
 
         // Update the top level view's visibilities
-        if (mConfig.launchedWithNoRecentTasks) {
+        if (launchState.launchedWithNoRecentTasks) {
             if (mEmptyView == null) {
                 mEmptyView = mEmptyViewStub.inflate();
             }
@@ -261,13 +243,13 @@
         mScrimViews.prepareEnterRecentsAnimation();
 
         // Keep track of whether we launched from the nav bar button or via alt-tab
-        if (mConfig.launchedWithAltTab) {
+        if (launchState.launchedWithAltTab) {
             MetricsLogger.count(this, "overview_trigger_alttab", 1);
         } else {
             MetricsLogger.count(this, "overview_trigger_nav_btn", 1);
         }
         // Keep track of whether we launched from an app or from home
-        if (mConfig.launchedFromAppWithThumbnail) {
+        if (launchState.launchedFromAppWithThumbnail) {
             MetricsLogger.count(this, "overview_source_app", 1);
             // If from an app, track the stack index of the app in the stack (for affiliated tasks)
             MetricsLogger.histogram(this, "overview_source_app_index", launchTaskIndexInStack);
@@ -281,6 +263,7 @@
 
     /** Dismisses recents if we are already visible and the intent is to toggle the recents view */
     boolean dismissRecentsToFocusedTaskOrHome(boolean checkFilteredStackState) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
         if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
             // If we currently have filtered stacks, then unfilter those first
@@ -289,7 +272,7 @@
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask()) return true;
             // If we launched from Home, then return to Home
-            if (mConfig.launchedFromHome) {
+            if (launchState.launchedFromHome) {
                 dismissRecentsToHomeRaw(true);
                 return true;
             }
@@ -339,7 +322,8 @@
         // initialized
         RecentsTaskLoader.initialize(this);
         SystemServicesProxy ssp = RecentsTaskLoader.getInstance().getSystemServicesProxy();
-        mConfig = RecentsConfiguration.reinitialize(this, ssp);
+        mConfig = RecentsConfiguration.initialize(this, ssp);
+        mConfig.update(this, ssp, ssp.getWindowRect());
 
         // Initialize the widget host (the host id is static and does not change)
         mAppWidgetHost = new RecentsAppWidgetHost(this, Constants.Values.App.AppWidgetHostId);
@@ -352,9 +336,7 @@
                 View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN |
                 View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION);
         mEmptyViewStub = (ViewStub) findViewById(R.id.empty_view_stub);
-        mDebugOverlayStub = (ViewStub) findViewById(R.id.debug_overlay_stub);
-        mScrimViews = new SystemBarScrimViews(this, mConfig);
-        inflateDebugOverlay();
+        mScrimViews = new SystemBarScrimViews(this);
 
         // Bind the search app widget when we first start up
         mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
@@ -366,32 +348,16 @@
         registerReceiver(mSystemBroadcastReceiver, filter);
     }
 
-    /** Inflates the debug overlay if debug mode is enabled. */
-    void inflateDebugOverlay() {
-        if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
-        if (mConfig.debugModeEnabled && mDebugOverlay == null) {
-            // Inflate the overlay and seek bars
-            mDebugOverlay = (DebugOverlayView) mDebugOverlayStub.inflate();
-            mDebugOverlay.setCallbacks(this);
-            mRecentsView.setDebugOverlay(mDebugOverlay);
-        }
-    }
-
     @Override
     protected void onNewIntent(Intent intent) {
         super.onNewIntent(intent);
         setIntent(intent);
-
-        // Clear any debug rects
-        if (mDebugOverlay != null) {
-            mDebugOverlay.clear();
-        }
     }
 
     @Override
     protected void onStart() {
         super.onStart();
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         MetricsLogger.visible(this, MetricsLogger.OVERVIEW_ACTIVITY);
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SystemServicesProxy ssp = loader.getSystemServicesProxy();
@@ -413,12 +379,13 @@
         // If this is a new instance from a configuration change, then we have to manually trigger
         // the enter animation state, or if recents was relaunched by AM, without going through
         // the normal mechanisms
-        boolean wasLaunchedByAm = !mConfig.launchedFromHome && !mConfig.launchedFromAppWithThumbnail;
-        if (mConfig.launchedHasConfigurationChanged || wasLaunchedByAm) {
+        boolean wasLaunchedByAm = !launchState.launchedFromHome &&
+                !launchState.launchedFromAppWithThumbnail;
+        if (launchState.launchedHasConfigurationChanged || wasLaunchedByAm) {
             onEnterAnimationTriggered();
         }
 
-        if (!mConfig.launchedHasConfigurationChanged) {
+        if (!launchState.launchedHasConfigurationChanged) {
             mRecentsView.disableLayersForOneFrame();
         }
     }
@@ -436,6 +403,7 @@
     protected void onStop() {
         super.onStop();
         MetricsLogger.hidden(this, MetricsLogger.OVERVIEW_ACTIVITY);
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         RecentsTaskLoader loader = RecentsTaskLoader.getInstance();
         SystemServicesProxy ssp = loader.getSystemServicesProxy();
         Recents.notifyVisibilityChanged(this, ssp, false);
@@ -452,12 +420,12 @@
         // Workaround for b/22542869, if the RecentsActivity is started again, but without going
         // through SystemUI, we need to reset the config launch flags to ensure that we do not
         // wait on the system to send a signal that was never queued.
-        mConfig.launchedFromHome = false;
-        mConfig.launchedFromSearchHome = false;
-        mConfig.launchedFromAppWithThumbnail = false;
-        mConfig.launchedToTaskId = -1;
-        mConfig.launchedWithAltTab = false;
-        mConfig.launchedHasConfigurationChanged = false;
+        launchState.launchedFromHome = false;
+        launchState.launchedFromSearchHome = false;
+        launchState.launchedFromAppWithThumbnail = false;
+        launchState.launchedToTaskId = -1;
+        launchState.launchedWithAltTab = false;
+        launchState.launchedHasConfigurationChanged = false;
     }
 
     @Override
@@ -509,8 +477,9 @@
     public boolean onKeyDown(int keyCode, KeyEvent event) {
         switch (keyCode) {
             case KeyEvent.KEYCODE_TAB: {
+                int altTabKeyDelay = getResources().getInteger(R.integer.recents_alt_tab_key_delay);
                 boolean hasRepKeyTimeElapsed = (SystemClock.elapsedRealtime() -
-                        mLastTabKeyEventTime) > mConfig.altTabKeyDelay;
+                        mLastTabKeyEventTime) > altTabKeyDelay;
                 if (event.getRepeatCount() <= 0 || hasRepKeyTimeElapsed) {
                     // Focus the next task in the stack
                     final boolean backward = event.isShiftPressed();
@@ -538,8 +507,6 @@
             default:
                 break;
         }
-        // Pass through the debug trigger
-        mDebugTrigger.onKeyEvent(keyCode);
         return super.onKeyDown(keyCode, event);
     }
 
@@ -550,40 +517,10 @@
 
     @Override
     public void onBackPressed() {
-        // Test mode where back does not do anything
-        if (mConfig.debugModeEnabled) return;
-
         // Dismiss Recents to the focused Task or Home
         dismissRecentsToFocusedTaskOrHome(true);
     }
 
-    /** Called when debug mode is triggered */
-    public void onDebugModeTriggered() {
-        if (mConfig.developerOptionsEnabled) {
-            if (Prefs.getBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, false /* boolean */)) {
-                // Disable the debug mode
-                Prefs.remove(this, Prefs.Key.DEBUG_MODE_ENABLED);
-                mConfig.debugModeEnabled = false;
-                inflateDebugOverlay();
-                if (mDebugOverlay != null) {
-                    mDebugOverlay.disable();
-                }
-            } else {
-                // Enable the debug mode
-                Prefs.putBoolean(this, Prefs.Key.DEBUG_MODE_ENABLED, true);
-                mConfig.debugModeEnabled = true;
-                inflateDebugOverlay();
-                if (mDebugOverlay != null) {
-                    mDebugOverlay.enable();
-                }
-            }
-            Toast.makeText(this, "Debug mode (" + Constants.Values.App.DebugModeVersion + ") " +
-                (mConfig.debugModeEnabled ? "Enabled" : "Disabled") + ", please restart Recents now",
-                Toast.LENGTH_SHORT).show();
-        }
-    }
-
-
     /**** RecentsResizeTaskDialog ****/
 
     private RecentsResizeTaskDialog getResizeTaskDebugDialog() {
@@ -655,16 +592,4 @@
             mRecentsView.setSearchBar(null);
         }
     }
-
-    /**** DebugOverlayView.DebugOverlayViewCallbacks ****/
-
-    @Override
-    public void onPrimarySeekBarChanged(float progress) {
-        // Do nothing
-    }
-
-    @Override
-    public void onSecondarySeekBarChanged(float progress) {
-        // Do nothing
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
new file mode 100644
index 0000000..e2e0e918
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivityLaunchState.java
@@ -0,0 +1,77 @@
+/*
+ * 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;
+
+/**
+ * The launch state of the RecentsActivity.
+ *
+ * TODO: We will be refactoring this out RecentsConfiguration.
+ * Current Constraints:
+ *  - needed in onStart() before onNewIntent()
+ *  - needs to be reset when Recents is hidden
+ *  - needs to be computed in Recents component
+ *  - needs to be accessible by views
+ */
+public class RecentsActivityLaunchState {
+
+    public RecentsConfiguration mConfig;
+
+    public boolean launchedWithAltTab;
+    public boolean launchedWithNoRecentTasks;
+    public boolean launchedFromAppWithThumbnail;
+    public boolean launchedFromHome;
+    public boolean launchedFromSearchHome;
+    public boolean launchedReuseTaskStackViews;
+    public boolean launchedHasConfigurationChanged;
+    public int launchedToTaskId;
+    public int launchedNumVisibleTasks;
+    public int launchedNumVisibleThumbnails;
+
+    RecentsActivityLaunchState(RecentsConfiguration config) {
+        mConfig = config;
+    }
+
+    /** Called when the configuration has changed, and we want to reset any configuration specific
+     * members. */
+    public void updateOnConfigurationChange() {
+        // Reset this flag on configuration change to ensure that we recreate new task views
+        launchedReuseTaskStackViews = false;
+        // Set this flag to indicate that the configuration has changed since Recents last launched
+        launchedHasConfigurationChanged = true;
+    }
+
+    /** Returns whether the status bar scrim should be animated when shown for the first time. */
+    public boolean shouldAnimateStatusBarScrim() {
+        return launchedFromHome;
+    }
+
+    /** Returns whether the status bar scrim should be visible. */
+    public boolean hasStatusBarScrim() {
+        return !launchedWithNoRecentTasks;
+    }
+
+    /** Returns whether the nav bar scrim should be animated when shown for the first time. */
+    public boolean shouldAnimateNavBarScrim() {
+        return true;
+    }
+
+    /** Returns whether the nav bar scrim should be visible. */
+    public boolean hasNavBarScrim() {
+        // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
+        return !launchedWithNoRecentTasks && mConfig.hasTransposedNavBar;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index b41b5e7..52b9521 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -16,27 +16,29 @@
 
 package com.android.systemui.recents;
 
-import android.app.ActivityManager;
 import android.content.Context;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Rect;
 import android.provider.Settings;
-import android.util.DisplayMetrics;
-import android.view.animation.AnimationUtils;
-import android.view.animation.Interpolator;
-
-import com.android.systemui.Prefs;
 import com.android.systemui.R;
-import com.android.systemui.recents.misc.Console;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
-
-/** A static Recents configuration for the current context
- * NOTE: We should not hold any references to a Context from a static instance */
+/**
+ * Application resources that can be retrieved from the application context and are not specifically
+ * tied to the current activity.
+ */
 public class RecentsConfiguration {
     static RecentsConfiguration sInstance;
-    static int sPrevConfigurationHashCode;
+
+    private static final int LARGE_SCREEN_MIN_DP = 600;
+    private static final int XLARGE_SCREEN_MIN_DP = 720;
+
+    // Variables that are used for global calculations
+    private static final float STACK_SIDE_PADDING_PHONES_PCT = 0.03333f;
+    private static final float STACK_SIZE_PADDING_TABLETS_PCT = 0.075f;
+    private static final float STACK_SIZE_PADDING_LARGE_TABLETS_PCT = 0.15f;
+    private static final int SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS = 64;
+    private static final int SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS = 72;
 
     /** Levels of svelte in increasing severity/austerity. */
     // No svelting.
@@ -50,123 +52,81 @@
     // Disable all thumbnail loading.
     public static final int SVELTE_DISABLE_LOADING = 3;
 
-    /** Interpolators */
-    public Interpolator fastOutSlowInInterpolator;
-    public Interpolator fastOutLinearInInterpolator;
-    public Interpolator linearOutSlowInInterpolator;
-    public Interpolator quintOutInterpolator;
+    // Launch states
+    public RecentsActivityLaunchState mLaunchState = new RecentsActivityLaunchState(this);
 
-    /** Filtering */
-    public int filteringCurrentViewsAnimDuration;
-    public int filteringNewViewsAnimDuration;
-
-    /** Insets */
-    public Rect systemInsets = new Rect();
-    public Rect displayRect = new Rect();
-
-    /** Layout */
-    boolean isLandscape;
+    // TODO: Values determined by the current context, needs to be refactored into something that is
+    //       agnostic of the activity context, but still calculable from the Recents component for
+    //       the transition into recents
     boolean hasTransposedSearchBar;
     boolean hasTransposedNavBar;
-
-    /** Loading */
-    public int maxNumTasksToLoad;
-
-    /** Search bar */
-    public int searchBarSpaceHeightPx;
-
-    /** Task stack */
-    public int taskStackScrollDuration;
-    public int taskStackMaxDim;
-    public int taskStackTopPaddingPx;
-    public int dismissAllButtonSizePx;
     public float taskStackWidthPaddingPct;
-    public float taskStackOverscrollPct;
 
-    /** Transitions */
-    public int transitionEnterFromAppDelay;
-    public int transitionEnterFromHomeDelay;
-
-    /** Task view animation and styles */
-    public int taskViewEnterFromAppDuration;
-    public int taskViewEnterFromHomeDuration;
-    public int taskViewEnterFromHomeStaggerDelay;
-    public int taskViewExitToAppDuration;
-    public int taskViewExitToHomeDuration;
-    public int taskViewRemoveAnimDuration;
-    public int taskViewRemoveAnimTranslationXPx;
-    public int taskViewTranslationZMinPx;
-    public int taskViewTranslationZMaxPx;
-    public int taskViewRoundedCornerRadiusPx;
-    public int taskViewHighlightPx;
-    public int taskViewAffiliateGroupEnterOffsetPx;
-    public float taskViewThumbnailAlpha;
-
-    /** Task bar colors */
-    public int taskBarViewDefaultBackgroundColor;
-    public int taskBarViewLightTextColor;
-    public int taskBarViewDarkTextColor;
-    public int taskBarViewHighlightColor;
-    public float taskBarViewAffiliationColorMinAlpha;
-
-    /** Task bar size & animations */
-    public int taskBarHeight;
-    public int taskBarDismissDozeDelaySeconds;
-
-    /** Nav bar scrim */
-    public int navBarScrimEnterDuration;
-
-    /** Launch states */
-    public boolean launchedWithAltTab;
-    public boolean launchedWithNoRecentTasks;
-    public boolean launchedFromAppWithThumbnail;
-    public boolean launchedFromHome;
-    public boolean launchedFromSearchHome;
-    public boolean launchedReuseTaskStackViews;
-    public boolean launchedHasConfigurationChanged;
-    public int launchedToTaskId;
-    public int launchedNumVisibleTasks;
-    public int launchedNumVisibleThumbnails;
+    // Since the positions in Recents has to be calculated globally (before the RecentsActivity
+    // starts), we need to calculate some resource values ourselves, instead of relying on framework
+    // resources.
+    public final boolean isLargeScreen;
+    public final boolean isXLargeScreen;
+    public final int smallestWidth;
 
     /** Misc **/
     public boolean useHardwareLayers;
-    public int altTabKeyDelay;
     public boolean fakeShadows;
+    public int svelteLevel;
+    public int searchBarSpaceHeightPx;
 
     /** Dev options and global settings */
     public boolean multiWindowEnabled;
     public boolean lockToAppEnabled;
-    public boolean developerOptionsEnabled;
-    public boolean debugModeEnabled;
-    public int svelteLevel;
 
     /** Private constructor */
-    private RecentsConfiguration(Context context) {
-        // Properties that don't have to be reloaded with each configuration change can be loaded
-        // here.
+    private RecentsConfiguration(Context context, SystemServicesProxy ssp) {
+        // Load only resources that can not change after the first load either through developer
+        // settings or via multi window
+        Context appContext = context.getApplicationContext();
+        Resources res = appContext.getResources();
+        useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
+        fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
+        svelteLevel = res.getInteger(R.integer.recents_svelte_level);
 
-        // Interpolators
-        fastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_slow_in);
-        fastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.fast_out_linear_in);
-        linearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.linear_out_slow_in);
-        quintOutInterpolator = AnimationUtils.loadInterpolator(context,
-                com.android.internal.R.interpolator.decelerate_quint);
+        float density = context.getResources().getDisplayMetrics().density;
+        smallestWidth = ssp.getDeviceSmallestWidth();
+        isLargeScreen = smallestWidth >= (int) (density * LARGE_SCREEN_MIN_DP);
+        isXLargeScreen = smallestWidth >= (int) (density * XLARGE_SCREEN_MIN_DP);
+        searchBarSpaceHeightPx = isLargeScreen ?
+                (int) (density * SEARCH_BAR_SPACE_HEIGHT_TABLETS_DPS) :
+                (int) (density * SEARCH_BAR_SPACE_HEIGHT_PHONES_DPS);
+        if (isLargeScreen) {
+            taskStackWidthPaddingPct = STACK_SIZE_PADDING_TABLETS_PCT;
+        } else if (isXLargeScreen) {
+            taskStackWidthPaddingPct = STACK_SIZE_PADDING_LARGE_TABLETS_PCT;
+        } else {
+            taskStackWidthPaddingPct = STACK_SIDE_PADDING_PHONES_PCT;
+        }
+    }
+
+    /**
+     * Updates the configuration based on the current state of the system
+     */
+    void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
+        // Only update resources that can change after the first load, either through developer
+        // settings or via multi window
+        lockToAppEnabled = ssp.getSystemSetting(context,
+                Settings.System.LOCK_TO_APP_ENABLED) != 0;
+        multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
+
+        // Recompute some values based on the given state, since we can not rely on the resource
+        // system to get certain values.
+        boolean isLandscape = windowRect.width() > windowRect.height();
+        hasTransposedNavBar = isLandscape && isLargeScreen && !isXLargeScreen;
+        hasTransposedSearchBar = isLandscape && isLargeScreen && !isXLargeScreen;
     }
 
     /** Updates the configuration to the current context */
-    public static RecentsConfiguration reinitialize(Context context, SystemServicesProxy ssp) {
+    public static RecentsConfiguration initialize(Context context, SystemServicesProxy ssp) {
         if (sInstance == null) {
-            sInstance = new RecentsConfiguration(context);
+            sInstance = new RecentsConfiguration(context, ssp);
         }
-        int configHashCode = context.getResources().getConfiguration().hashCode();
-        if (sPrevConfigurationHashCode != configHashCode) {
-            sInstance.update(context);
-            sPrevConfigurationHashCode = configHashCode;
-        }
-        sInstance.updateOnReinitialize(context, ssp);
         return sInstance;
     }
 
@@ -175,145 +135,18 @@
         return sInstance;
     }
 
-    /** Updates the state, given the specified context */
-    void update(Context context) {
-        Resources res = context.getResources();
-        DisplayMetrics dm = res.getDisplayMetrics();
-
-        // Debug mode
-        debugModeEnabled = Prefs.getBoolean(context, Prefs.Key.DEBUG_MODE_ENABLED,
-                false /* defaultValue */);
-        if (debugModeEnabled) {
-            Console.Enabled = true;
-        }
-
-        // Layout
-        isLandscape = res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
-        hasTransposedSearchBar = res.getBoolean(R.bool.recents_has_transposed_search_bar);
-        hasTransposedNavBar = res.getBoolean(R.bool.recents_has_transposed_nav_bar);
-
-        // Insets
-        displayRect.set(0, 0, dm.widthPixels, dm.heightPixels);
-
-        // Filtering
-        filteringCurrentViewsAnimDuration =
-                res.getInteger(R.integer.recents_filter_animate_current_views_duration);
-        filteringNewViewsAnimDuration =
-                res.getInteger(R.integer.recents_filter_animate_new_views_duration);
-
-        // Loading
-        maxNumTasksToLoad = ActivityManager.getMaxRecentTasksStatic();
-
-        // Search Bar
-        searchBarSpaceHeightPx = res.getDimensionPixelSize(R.dimen.recents_search_bar_space_height);
-
-        // Task stack
-        taskStackScrollDuration =
-                res.getInteger(R.integer.recents_animate_task_stack_scroll_duration);
-        taskStackWidthPaddingPct = res.getFloat(R.dimen.recents_stack_width_padding_percentage);
-        taskStackOverscrollPct = res.getFloat(R.dimen.recents_stack_overscroll_percentage);
-        taskStackMaxDim = res.getInteger(R.integer.recents_max_task_stack_view_dim);
-        taskStackTopPaddingPx = res.getDimensionPixelSize(R.dimen.recents_stack_top_padding);
-        dismissAllButtonSizePx = res.getDimensionPixelSize(R.dimen.recents_dismiss_all_button_size);
-
-        // Transition
-        transitionEnterFromAppDelay =
-                res.getInteger(R.integer.recents_enter_from_app_transition_duration);
-        transitionEnterFromHomeDelay =
-                res.getInteger(R.integer.recents_enter_from_home_transition_duration);
-
-        // Task view animation and styles
-        taskViewEnterFromAppDuration =
-                res.getInteger(R.integer.recents_task_enter_from_app_duration);
-        taskViewEnterFromHomeDuration =
-                res.getInteger(R.integer.recents_task_enter_from_home_duration);
-        taskViewEnterFromHomeStaggerDelay =
-                res.getInteger(R.integer.recents_task_enter_from_home_stagger_delay);
-        taskViewExitToAppDuration =
-                res.getInteger(R.integer.recents_task_exit_to_app_duration);
-        taskViewExitToHomeDuration =
-                res.getInteger(R.integer.recents_task_exit_to_home_duration);
-        taskViewRemoveAnimDuration =
-                res.getInteger(R.integer.recents_animate_task_view_remove_duration);
-        taskViewRemoveAnimTranslationXPx =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_remove_anim_translation_x);
-        taskViewRoundedCornerRadiusPx =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_rounded_corners_radius);
-        taskViewHighlightPx = res.getDimensionPixelSize(R.dimen.recents_task_view_highlight);
-        taskViewTranslationZMinPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_min);
-        taskViewTranslationZMaxPx = res.getDimensionPixelSize(R.dimen.recents_task_view_z_max);
-        taskViewAffiliateGroupEnterOffsetPx =
-                res.getDimensionPixelSize(R.dimen.recents_task_view_affiliate_group_enter_offset);
-        taskViewThumbnailAlpha = res.getFloat(R.dimen.recents_task_view_thumbnail_alpha);
-
-        // Task bar colors
-        taskBarViewDefaultBackgroundColor = context.getColor(
-                R.color.recents_task_bar_default_background_color);
-        taskBarViewLightTextColor = context.getColor(R.color.recents_task_bar_light_text_color);
-        taskBarViewDarkTextColor = context.getColor(R.color.recents_task_bar_dark_text_color);
-        taskBarViewHighlightColor = context.getColor(R.color.recents_task_bar_highlight_color);
-        taskBarViewAffiliationColorMinAlpha = res.getFloat(
-                R.dimen.recents_task_affiliation_color_min_alpha_percentage);
-
-        // Task bar size & animations
-        taskBarHeight = res.getDimensionPixelSize(R.dimen.recents_task_bar_height);
-        taskBarDismissDozeDelaySeconds =
-                res.getInteger(R.integer.recents_task_bar_dismiss_delay_seconds);
-
-        // Nav bar scrim
-        navBarScrimEnterDuration =
-                res.getInteger(R.integer.recents_nav_bar_scrim_enter_duration);
-
-        // Misc
-        useHardwareLayers = res.getBoolean(R.bool.config_recents_use_hardware_layers);
-        altTabKeyDelay = res.getInteger(R.integer.recents_alt_tab_key_delay);
-        fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
-        svelteLevel = res.getInteger(R.integer.recents_svelte_level);
-    }
-
-    /** Updates the system insets */
-    public void updateSystemInsets(Rect insets) {
-        systemInsets.set(insets);
-    }
-
-    /** Updates the states that need to be re-read whenever we re-initialize. */
-    void updateOnReinitialize(Context context, SystemServicesProxy ssp) {
-        // Check if the developer options are enabled
-        developerOptionsEnabled = ssp.getGlobalSetting(context,
-                Settings.Global.DEVELOPMENT_SETTINGS_ENABLED) != 0;
-        lockToAppEnabled = ssp.getSystemSetting(context,
-                Settings.System.LOCK_TO_APP_ENABLED) != 0;
-        multiWindowEnabled = "true".equals(ssp.getSystemProperty("persist.sys.debug.multi_window"));
+    /**
+     * Returns the activity launch state.
+     * TODO: This will be refactored out of RecentsConfiguration.
+     */
+    public RecentsActivityLaunchState getLaunchState() {
+        return mLaunchState;
     }
 
     /** Called when the configuration has changed, and we want to reset any configuration specific
      * members. */
     public void updateOnConfigurationChange() {
-        // Reset this flag on configuration change to ensure that we recreate new task views
-        launchedReuseTaskStackViews = false;
-        // Set this flag to indicate that the configuration has changed since Recents last launched
-        launchedHasConfigurationChanged = true;
-    }
-
-    /** Returns whether the status bar scrim should be animated when shown for the first time. */
-    public boolean shouldAnimateStatusBarScrim() {
-        return launchedFromHome;
-    }
-
-    /** Returns whether the status bar scrim should be visible. */
-    public boolean hasStatusBarScrim() {
-        return !launchedWithNoRecentTasks;
-    }
-
-    /** Returns whether the nav bar scrim should be animated when shown for the first time. */
-    public boolean shouldAnimateNavBarScrim() {
-        return true;
-    }
-
-    /** Returns whether the nav bar scrim should be visible. */
-    public boolean hasNavBarScrim() {
-        // Only show the scrim if we have recent tasks, and if the nav bar is not transposed
-        return !launchedWithNoRecentTasks && (!hasTransposedNavBar || !isLandscape);
+        mLaunchState.updateOnConfigurationChange();
     }
 
     /**
@@ -322,14 +155,17 @@
      */
     public void getAvailableTaskStackBounds(Rect windowBounds, int topInset,
             int rightInset, Rect searchBarBounds, Rect taskStackBounds) {
-        if (isLandscape && hasTransposedSearchBar) {
-            // In landscape, the search bar appears on the left, but we overlay it on top
-            taskStackBounds.set(windowBounds.left, windowBounds.top + topInset,
-                    windowBounds.right - rightInset, windowBounds.bottom);
+        if (hasTransposedNavBar) {
+            // In landscape phones, the search bar appears on the left, but we overlay it on top
+            int swInset = getInsetToSmallestWidth(windowBounds.right - rightInset -
+                    windowBounds.left);
+            taskStackBounds.set(windowBounds.left + swInset, windowBounds.top + topInset,
+                    windowBounds.right - swInset - rightInset, windowBounds.bottom);
         } else {
             // In portrait, the search bar appears on the top (which already has the inset)
-            taskStackBounds.set(windowBounds.left, searchBarBounds.bottom,
-                    windowBounds.right, windowBounds.bottom);
+            int swInset = getInsetToSmallestWidth(windowBounds.right - windowBounds.left);
+            taskStackBounds.set(windowBounds.left + swInset, searchBarBounds.bottom,
+                    windowBounds.right - swInset, windowBounds.bottom);
         }
     }
 
@@ -340,8 +176,8 @@
     public void getSearchBarBounds(Rect windowBounds, int topInset, Rect searchBarSpaceBounds) {
         // Return empty rects if search is not enabled
         int searchBarSize = searchBarSpaceHeightPx;
-        if (isLandscape && hasTransposedSearchBar) {
-            // In landscape, the search bar appears on the left
+        if (hasTransposedSearchBar) {
+            // In landscape phones, the search bar appears on the left
             searchBarSpaceBounds.set(windowBounds.left, windowBounds.top + topInset,
                     windowBounds.left + searchBarSize, windowBounds.bottom);
         } else {
@@ -350,4 +186,14 @@
                     windowBounds.right, windowBounds.top + topInset + searchBarSize);
         }
     }
+
+    /**
+     * Constrain the width of the landscape stack to the smallest width of the device.
+     */
+    private int getInsetToSmallestWidth(int availableWidth) {
+        if (availableWidth > smallestWidth) {
+            return (availableWidth - smallestWidth) / 2;
+        }
+        return 0;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
index 703c7d2..59df293 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsResizeTaskDialog.java
@@ -16,17 +16,18 @@
 
 package com.android.systemui.recents;
 
+import android.app.ActivityManager;
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.app.DialogFragment;
 import android.app.FragmentManager;
-import android.content.Context;
 import android.content.DialogInterface;
 import android.graphics.Rect;
 import android.os.Bundle;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.Button;
+import android.widget.Toast;
 import com.android.systemui.R;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.RecentsTaskLoader;
@@ -50,10 +51,18 @@
     private static final int PLACE_BOTTOM_LEFT = 7;
     private static final int PLACE_BOTTOM_RIGHT = 8;
     private static final int PLACE_FULL = 9;
+    private static final int PLACE_DOCK_LEFT = 10;
+    private static final int PLACE_DOCK_RIGHT = 11;
+    private static final int PLACE_DOCK_TOP = 12;
+    private static final int PLACE_DOCK_BOTTOM = 13;
 
     // The button resource ID combined with the arrangement command.
     private static final int[][] BUTTON_DEFINITIONS =
-           {{R.id.place_left, PLACE_LEFT},
+           {{R.id.place_dock_left, PLACE_DOCK_LEFT},
+            {R.id.place_dock_right, PLACE_DOCK_RIGHT},
+            {R.id.place_dock_top, PLACE_DOCK_TOP},
+            {R.id.place_dock_bottom, PLACE_DOCK_BOTTOM},
+            {R.id.place_left, PLACE_LEFT},
             {R.id.place_right, PLACE_RIGHT},
             {R.id.place_top, PLACE_TOP},
             {R.id.place_bottom, PLACE_BOTTOM},
@@ -72,6 +81,12 @@
     private Rect[] mBounds = {new Rect(), new Rect(), new Rect(), new Rect()};
     private Task[] mTasks = {null, null, null, null};
 
+    /**
+     * Called by FragmentManager
+     */
+    public RecentsResizeTaskDialog() {
+    }
+
     public RecentsResizeTaskDialog(FragmentManager mgr, RecentsActivity activity) {
         mFragmentManager = mgr;
         mRecentsActivity = activity;
@@ -82,13 +97,11 @@
     void showResizeTaskDialog(Task mainTask, RecentsView rv) {
         mTasks[0] = mainTask;
         mRecentsView = rv;
-
-        show(mFragmentManager, TAG);
+        showAllowingStateLoss(mFragmentManager, TAG);
     }
 
     /** Creates a new resize-task dialog. */
-    private void createResizeTaskDialog(final Context context, LayoutInflater inflater,
-            AlertDialog.Builder builder) {
+    private void createResizeTaskDialog(LayoutInflater inflater, AlertDialog.Builder builder) {
         builder.setTitle(R.string.recents_caption_resize);
         mResizeTaskDialogContent =
                 inflater.inflate(R.layout.recents_task_resize_dialog, null, false);
@@ -100,7 +113,17 @@
                 b.setOnClickListener(
                         new View.OnClickListener() {
                             public void onClick(View v) {
-                                placeTasks(action);
+                                switch (action) {
+                                    case PLACE_DOCK_LEFT:
+                                    case PLACE_DOCK_RIGHT:
+                                    case PLACE_DOCK_TOP:
+                                    case PLACE_DOCK_BOTTOM:
+                                        placeDockTasks(action);
+                                        break;
+                                    default:
+                                        placeTasks(action);
+                                        break;
+                                }
                             }
                         });
             }
@@ -109,7 +132,7 @@
         builder.setNegativeButton(R.string.cancel, new DialogInterface.OnClickListener() {
             @Override
             public void onClick(DialogInterface dialog, int which) {
-                dismiss();
+                dismissAllowingStateLoss();
             }
         });
 
@@ -118,7 +141,7 @@
 
     /** Helper function to place window(s) on the display according to an arrangement request. */
     private void placeTasks(int arrangement) {
-        Rect rect = mSsp.getWindowRect();
+        Rect rect = mSsp.getDisplayRect();
         for (int i = 0; i < mBounds.length; ++i) {
             mBounds[i].set(rect);
             if (i != 0) {
@@ -193,7 +216,7 @@
                 break;
             case PLACE_FULL:
                 // Nothing to change.
-                mBounds[0] = null;
+                mBounds[0] = new Rect();
                 break;
         }
 
@@ -207,7 +230,7 @@
         }
 
         // Get rid of the dialog.
-        dismiss();
+        dismissAllowingStateLoss();
         mRecentsActivity.dismissRecentsToHomeWithoutTransitionAnimation();
 
         // In debug mode, we force all task to be resizeable regardless of the
@@ -229,12 +252,44 @@
         }
     }
 
+    /**
+     * Helper function to place docked window(s) on the display according to an arrangement request.
+     */
+    private void placeDockTasks(int arrangement) {
+        int createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+        switch (arrangement) {
+            case PLACE_DOCK_LEFT:
+                createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+                break;
+            case PLACE_DOCK_TOP:
+                createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+                break;
+            case PLACE_DOCK_RIGHT:
+                createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+                break;
+            case PLACE_DOCK_BOTTOM:
+                createMode = ActivityManager.DOCKED_STACK_CREATE_MODE_BOTTOM_OR_RIGHT;
+                break;
+        }
+
+        // Dismiss the dialog before trying to launch the task
+        dismissAllowingStateLoss();
+
+        if (mTasks[0].key.stackId != ActivityManager.DOCKED_STACK_ID) {
+            int taskId = mTasks[0].key.id;
+            mSsp.setTaskResizeable(taskId);
+            mSsp.dockTask(taskId, createMode);
+            mRecentsView.launchTask(mTasks[0], null);
+        } else {
+            Toast.makeText(getContext(), "Already docked", Toast.LENGTH_SHORT);
+        }
+    }
+
     @Override
     public Dialog onCreateDialog(Bundle args) {
-        final Context context = this.getActivity();
         LayoutInflater inflater = getActivity().getLayoutInflater();
         AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
-        createResizeTaskDialog(context, inflater, builder);
+        createResizeTaskDialog(inflater, builder);
         return builder.create();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index cbf5c05..231843e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -39,7 +39,6 @@
 import android.widget.FrameLayout;
 import android.widget.LinearLayout;
 import android.widget.TextView;
-
 import com.android.systemui.R;
 
 import java.util.ArrayList;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java b/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
deleted file mode 100644
index fbf8a86..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/DebugTrigger.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.misc;
-
-import android.os.Handler;
-import android.os.SystemClock;
-import android.view.KeyEvent;
-import com.android.systemui.recents.Constants;
-
-/**
- * A trigger for catching a debug chord.
- * We currently use volume up then volume down to trigger this mode.
- */
-public class DebugTrigger {
-
-    Handler mHandler;
-    Runnable mTriggeredRunnable;
-
-    int mLastKeyCode;
-    long mLastKeyCodeTime;
-
-    public DebugTrigger(Runnable triggeredRunnable) {
-        mHandler = new Handler();
-        mTriggeredRunnable = triggeredRunnable;
-    }
-
-    /** Resets the debug trigger */
-    void reset() {
-        mLastKeyCode = 0;
-        mLastKeyCodeTime = 0;
-    }
-
-    /**
-     * Processes a key event and tests if it is a part of the trigger. If the chord is complete,
-     * then we just call the callback.
-     */
-    public void onKeyEvent(int keyCode) {
-        if (!Constants.DebugFlags.App.EnableDebugMode) return;
-
-        if (mLastKeyCode == 0) {
-            if (keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
-                mLastKeyCode = keyCode;
-                mLastKeyCodeTime = SystemClock.uptimeMillis();
-                return;
-            }
-        } else {
-            if (mLastKeyCode == KeyEvent.KEYCODE_VOLUME_UP &&
-                    keyCode == KeyEvent.KEYCODE_VOLUME_DOWN) {
-                if ((SystemClock.uptimeMillis() - mLastKeyCodeTime) < 750) {
-                    mTriggeredRunnable.run();
-                }
-            }
-        }
-        reset();
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 5790ca6..b6d25f5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -55,18 +55,18 @@
 import android.provider.Settings;
 import android.util.Log;
 import android.util.MutableBoolean;
+import android.util.MutableFloat;
+import android.util.MutableInt;
 import android.util.Pair;
-import android.util.SparseArray;
+import android.util.Size;
 import android.view.Display;
 import android.view.WindowManager;
 import android.view.accessibility.AccessibilityManager;
-
 import com.android.internal.app.AssistUtils;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -282,6 +282,30 @@
         }
     }
 
+    /**
+     * Resizes the given task to the new bounds.
+     */
+    public void resizeTask(int taskId, Rect bounds) {
+        if (mIam == null) return;
+
+        try {
+            mIam.resizeTask(taskId, bounds, ActivityManager.RESIZE_MODE_FORCED);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
+    /** Docks a task to the side of the screen. */
+    public void dockTask(int taskId, int createMode) {
+        if (mIam == null) return;
+
+        try {
+            mIam.moveTaskToDockedStack(taskId, createMode, true);
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+    }
+
     /** Returns the focused stack id. */
     public int getFocusedStack() {
         if (mIam == null) return -1;
@@ -637,7 +661,32 @@
     }
 
     /**
-     * Returns the window rect.
+     * Returns the smallest width/height.
+     */
+    public int getDeviceSmallestWidth() {
+        if (mWm == null) return 0;
+
+        Point smallestSizeRange = new Point();
+        Point largestSizeRange = new Point();
+        mWm.getDefaultDisplay().getCurrentSizeRange(smallestSizeRange, largestSizeRange);
+        return smallestSizeRange.x;
+    }
+
+    /**
+     * Returns the display rect.
+     */
+    public Rect getDisplayRect() {
+        Rect displayRect = new Rect();
+        if (mWm == null) return displayRect;
+
+        Point p = new Point();
+        mWm.getDefaultDisplay().getRealSize(p);
+        displayRect.set(0, 0, p.x, p.y);
+        return displayRect;
+    }
+
+    /**
+     * Returns the window rect for the RecentsActivity, based on the dimensions of the home stack.
      */
     public Rect getWindowRect() {
         Rect windowRect = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 649cb4d..6ef7253 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -23,7 +23,6 @@
 import android.graphics.drawable.Drawable;
 import android.os.UserHandle;
 import android.util.Log;
-import android.util.SparseArray;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.SystemServicesProxy;
 
@@ -76,7 +75,7 @@
      * An optimization to preload the raw list of tasks.
      */
     public synchronized void preloadRawTasks(boolean isTopTaskHome) {
-        mRawTasks = mSystemServicesProxy.getRecentTasks(mConfig.maxNumTasksToLoad,
+        mRawTasks = mSystemServicesProxy.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
                 UserHandle.CURRENT.getIdentifier(), isTopTaskHome);
         Collections.reverse(mRawTasks);
 
@@ -125,7 +124,7 @@
                     activityLabel, mSystemServicesProxy, res);
             Drawable activityIcon = loader.getAndUpdateActivityIcon(taskKey, t.taskDescription,
                     mSystemServicesProxy, res, infoHandle, false);
-            int activityColor = loader.getActivityPrimaryColor(t.taskDescription, mConfig);
+            int activityColor = loader.getActivityPrimaryColor(t.taskDescription, res);
 
             // Update the activity info cache
             if (!hadCachedActivityInfo && infoHandle.info != null) {
@@ -153,7 +152,7 @@
         // Initialize the stacks
         mStack = new TaskStack();
         mStack.setTasks(stackTasks);
-        mStack.createAffiliatedGroupings(mConfig);
+        mStack.createAffiliatedGroupings(mContext);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index ad25c85..760382e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -27,7 +27,6 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.util.Log;
-
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
@@ -248,7 +247,7 @@
 }
 
 /* Recents task loader
- * NOTE: We should not hold any references to a Context from a static instance */
+ * NOTE: We should not hold any references to non-application Context from a static instance */
 public class RecentsTaskLoader {
     private static final String TAG = "RecentsTaskLoader";
 
@@ -438,12 +437,11 @@
     }
 
     /** Returns the activity's primary color. */
-    public int getActivityPrimaryColor(ActivityManager.TaskDescription td,
-            RecentsConfiguration config) {
+    public int getActivityPrimaryColor(ActivityManager.TaskDescription td, Resources res) {
         if (td != null && td.getPrimaryColor() != 0) {
             return td.getPrimaryColor();
         }
-        return config.taskBarViewDefaultBackgroundColor;
+        return res.getColor(R.color.recents_task_bar_default_background_color);
     }
 
     /** Returns the size of the app icon cache. */
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 a760a41..20d9203 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -16,12 +16,12 @@
 
 package com.android.systemui.recents.model;
 
+import android.content.Context;
 import android.graphics.Color;
-import android.graphics.Rect;
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.NamedCounter;
 import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -368,7 +368,7 @@
     /**
      * Temporary: This method will simulate affiliation groups by
      */
-    public void createAffiliatedGroupings(RecentsConfiguration config) {
+    public void createAffiliatedGroupings(Context context) {
         if (Constants.DebugFlags.App.EnableSimulatedTaskGroups) {
             HashMap<Task.TaskKey, Task> taskMap = new HashMap<Task.TaskKey, Task>();
             // Sort all tasks by increasing firstActiveTime of the task
@@ -453,7 +453,8 @@
                 tasksMap.put(t.key, t);
             }
             // Update the task colors for each of the groups
-            float minAlpha = config.taskBarViewAffiliationColorMinAlpha;
+            float minAlpha = context.getResources().getFloat(
+                    R.dimen.recents_task_affiliation_color_min_alpha_percentage);
             int taskGroupCount = mGroups.size();
             for (int i = 0; i < taskGroupCount; i++) {
                 TaskGrouping group = mGroups.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java b/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
deleted file mode 100644
index 452830d..0000000
--- a/packages/SystemUI/src/com/android/systemui/recents/views/DebugOverlayView.java
+++ /dev/null
@@ -1,190 +0,0 @@
-/*
- * 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.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Paint;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.util.Pair;
-import android.view.View;
-import android.widget.FrameLayout;
-import android.widget.SeekBar;
-import com.android.systemui.R;
-import com.android.systemui.recents.RecentsConfiguration;
-
-import java.util.ArrayList;
-
-/**
- * A full screen overlay layer that allows us to draw views from throughout the system on the top
- * most layer.
- */
-public class DebugOverlayView extends FrameLayout implements SeekBar.OnSeekBarChangeListener {
-
-    public interface DebugOverlayViewCallbacks {
-        public void onPrimarySeekBarChanged(float progress);
-        public void onSecondarySeekBarChanged(float progress);
-    }
-
-    final static int sCornerRectSize = 50;
-
-    RecentsConfiguration mConfig;
-    DebugOverlayViewCallbacks mCb;
-
-    ArrayList<Pair<Rect, Integer>> mRects = new ArrayList<Pair<Rect, Integer>>();
-    String mText;
-    Paint mDebugOutline = new Paint();
-    Paint mTmpPaint = new Paint();
-    Rect mTmpRect = new Rect();
-    boolean mEnabled = true;
-
-    SeekBar mPrimarySeekBar;
-    SeekBar mSecondarySeekBar;
-
-    public DebugOverlayView(Context context) {
-        this(context, null);
-    }
-
-    public DebugOverlayView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public DebugOverlayView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-        mConfig = RecentsConfiguration.getInstance();
-        mDebugOutline.setColor(0xFFff0000);
-        mDebugOutline.setStyle(Paint.Style.STROKE);
-        mDebugOutline.setStrokeWidth(8f);
-        setWillNotDraw(false);
-    }
-
-    public void setCallbacks(DebugOverlayViewCallbacks cb) {
-        mCb = cb;
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        mPrimarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_1);
-        mPrimarySeekBar.setOnSeekBarChangeListener(this);
-        mSecondarySeekBar = (SeekBar) findViewById(R.id.debug_seek_bar_2);
-        mSecondarySeekBar.setOnSeekBarChangeListener(this);
-    }
-
-    /** Enables the debug overlay drawing. */
-    public void enable() {
-        mEnabled = true;
-        setVisibility(View.VISIBLE);
-    }
-
-    /** Disables the debug overlay drawing. */
-    public void disable() {
-        mEnabled = false;
-        setVisibility(View.GONE);
-    }
-
-    /** Clears all debug rects. */
-    public void clear() {
-        mRects.clear();
-    }
-
-    /** Adds a rect to be drawn. */
-    void addRect(Rect r, int color) {
-        mRects.add(new Pair<Rect, Integer>(r, color));
-        invalidate();
-    }
-
-    /** Adds a view's global rect to be drawn. */
-    void addViewRect(View v, int color) {
-        Rect vr = new Rect();
-        v.getGlobalVisibleRect(vr);
-        mRects.add(new Pair<Rect, Integer>(vr, color));
-        invalidate();
-    }
-
-    /** Adds a rect, relative to a given view to be drawn. */
-    void addRectRelativeToView(View v, Rect r, int color) {
-        Rect vr = new Rect();
-        v.getGlobalVisibleRect(vr);
-        r.offsetTo(vr.left, vr.top);
-        mRects.add(new Pair<Rect, Integer>(r, color));
-        invalidate();
-    }
-
-    /** Sets the debug text at the bottom of the screen. */
-    void setText(String message) {
-        mText = message;
-        invalidate();
-    }
-
-    @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        addRect(new Rect(0, 0, sCornerRectSize, sCornerRectSize), 0xFFff0000);
-        addRect(new Rect(getMeasuredWidth() - sCornerRectSize, getMeasuredHeight() - sCornerRectSize,
-                getMeasuredWidth(), getMeasuredHeight()), 0xFFff0000);
-    }
-
-    @Override
-    protected void onDraw(Canvas canvas) {
-        if (mEnabled) {
-            // Draw the outline
-            canvas.drawRect(0, 0, getMeasuredWidth(), getMeasuredHeight(), mDebugOutline);
-
-            // Draw the rects
-            int numRects = mRects.size();
-            for (int i = 0; i < numRects; i++) {
-                Pair<Rect, Integer> r = mRects.get(i);
-                mTmpPaint.setColor(r.second);
-                canvas.drawRect(r.first, mTmpPaint);
-            }
-
-            // Draw the text
-            if (mText != null && mText.length() > 0) {
-                mTmpPaint.setColor(0xFFff0000);
-                mTmpPaint.setTextSize(60);
-                mTmpPaint.getTextBounds(mText, 0, 1, mTmpRect);
-                canvas.drawText(mText, 10f, getMeasuredHeight() - mTmpRect.height() - mConfig.systemInsets.bottom, mTmpPaint);
-            }
-        }
-    }
-
-    /**** SeekBar.OnSeekBarChangeListener Implementation ****/
-
-    @Override
-    public void onStopTrackingTouch(SeekBar seekBar) {
-        // Do nothing
-    }
-
-    @Override
-    public void onStartTrackingTouch(SeekBar seekBar) {
-        // Do nothing
-    }
-
-    @Override
-    public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
-        if (seekBar == mPrimarySeekBar) {
-            mCb.onPrimarySeekBarChanged((float) progress / mPrimarySeekBar.getMax());
-        } else if (seekBar == mSecondarySeekBar) {
-            mCb.onSecondarySeekBarChanged((float) progress / mSecondarySeekBar.getMax());
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
index 509ad1b..682fd8f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FakeShadowDrawable.java
@@ -28,7 +28,6 @@
 import android.graphics.Shader;
 import android.graphics.drawable.Drawable;
 import android.util.Log;
-
 import com.android.systemui.R;
 import com.android.systemui.recents.RecentsConfiguration;
 
@@ -90,7 +89,8 @@
         mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
         mCornerShadowPaint.setStyle(Paint.Style.FILL);
         mCornerShadowPaint.setDither(true);
-        mCornerRadius = config.taskViewRoundedCornerRadiusPx;
+        mCornerRadius = resources.getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
         mCardBounds = new RectF();
         mEdgeShadowPaint = new Paint(mCornerShadowPaint);
     }
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 c7d1dd1..73c9be9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -38,8 +38,9 @@
 import android.view.View;
 import android.view.WindowInsets;
 import android.view.WindowManagerGlobal;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
@@ -78,12 +79,14 @@
 
     RecentsConfiguration mConfig;
     LayoutInflater mInflater;
-    DebugOverlayView mDebugOverlay;
 
     ArrayList<TaskStack> mStacks;
     TaskStackView mTaskStackView;
     RecentsAppWidgetHostView mSearchBar;
     RecentsViewCallbacks mCb;
+    Interpolator mFastOutSlowInInterpolator;
+
+    Rect mSystemInsets = new Rect();
 
     public RecentsView(Context context) {
         super(context);
@@ -101,6 +104,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mConfig = RecentsConfiguration.getInstance();
         mInflater = LayoutInflater.from(context);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
     /** Sets the callbacks */
@@ -108,14 +113,9 @@
         mCb = cb;
     }
 
-    /** Sets the debug overlay */
-    public void setDebugOverlay(DebugOverlayView overlay) {
-        mDebugOverlay = overlay;
-    }
-
     /** Set/get the bsp root node */
     public void setTaskStack(TaskStack stack) {
-        if (mConfig.launchedReuseTaskStackViews) {
+        if (mConfig.getLaunchState().launchedReuseTaskStackViews) {
             if (mTaskStackView != null) {
                 // If onRecentsHidden is not triggered, we need to the stack view again here
                 mTaskStackView.reset();
@@ -134,11 +134,6 @@
             addView(mTaskStackView);
         }
 
-        // Enable debug mode drawing on all the stacks if necessary
-        if (mConfig.debugModeEnabled) {
-            mTaskStackView.setDebugOverlay(mDebugOverlay);
-        }
-
         // Trigger a new layout
         requestLayout();
     }
@@ -195,7 +190,8 @@
             for (int j = 0; j < taskViewCount; j++) {
                 TaskView tv = taskViews.get(j);
                 if (tv.getTask() == task) {
-                    onTaskViewClicked(mTaskStackView, tv, stack, task, false, true, taskBounds);
+                    onTaskViewClicked(mTaskStackView, tv, stack, task, false, taskBounds != null,
+                            taskBounds);
                     return true;
                 }
             }
@@ -288,7 +284,7 @@
         // Get the search bar bounds and measure the search bar layout
         Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
-            mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
+            mConfig.getSearchBarBounds(new Rect(0, 0, width, height), mSystemInsets.top,
                     searchBarSpaceBounds);
             mSearchBar.measure(
                     MeasureSpec.makeMeasureSpec(searchBarSpaceBounds.width(), MeasureSpec.EXACTLY),
@@ -296,8 +292,8 @@
         }
 
         Rect taskStackBounds = new Rect();
-        mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mConfig.systemInsets.top,
-                mConfig.systemInsets.right, searchBarSpaceBounds, taskStackBounds);
+        mConfig.getAvailableTaskStackBounds(new Rect(0, 0, width, height), mSystemInsets.top,
+                mSystemInsets.right, searchBarSpaceBounds, taskStackBounds);
         if (mTaskStackView != null && mTaskStackView.getVisibility() != GONE) {
             mTaskStackView.setTaskStackBounds(taskStackBounds);
             mTaskStackView.measure(widthMeasureSpec, heightMeasureSpec);
@@ -316,7 +312,7 @@
         Rect searchBarSpaceBounds = new Rect();
         if (mSearchBar != null) {
             mConfig.getSearchBarBounds(measuredRect,
-                    mConfig.systemInsets.top, searchBarSpaceBounds);
+                    mSystemInsets.top, searchBarSpaceBounds);
             mSearchBar.layout(searchBarSpaceBounds.left, searchBarSpaceBounds.top,
                     searchBarSpaceBounds.right, searchBarSpaceBounds.bottom);
         }
@@ -328,8 +324,7 @@
 
     @Override
     public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        // Update the configuration with the latest system insets and trigger a relayout
-        mConfig.updateSystemInsets(insets.getSystemWindowInsets());
+        mSystemInsets.set(insets.getSystemWindowInsets());
         requestLayout();
         return insets.consumeSystemWindowInsets();
     }
@@ -558,7 +553,7 @@
             // outside the display rect (to ensure we don't animate from too far away)
             sourceView = stackView;
             offsetX = transform.rect.left;
-            offsetY = mConfig.displayRect.height();
+            offsetY = getMeasuredHeight();
         } else {
             sourceView = tv.mThumbnailView;
         }
@@ -589,22 +584,15 @@
             }
             postDrawHeaderThumbnailTransitionRunnable(stackView, tv, offsetX, offsetY, stackScroll,
                     animStartedListener);
-            if (mConfig.multiWindowEnabled) {
-                opts = ActivityOptions.makeCustomAnimation(sourceView.getContext(),
-                        R.anim.recents_from_unknown_enter,
-                        R.anim.recents_from_unknown_exit,
-                        sourceView.getHandler(), animStartedListener);
-            } else {
-                opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
-                        Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
-                        offsetX, offsetY, transform.rect.width(), transform.rect.height(),
-                        sourceView.getHandler(), animStartedListener);
-            }
+            opts = ActivityOptions.makeThumbnailAspectScaleUpAnimation(sourceView,
+                    Bitmap.createBitmap(1, 1, Bitmap.Config.ALPHA_8).createAshmemBitmap(),
+                    offsetX, offsetY, transform.rect.width(), transform.rect.height(),
+                    sourceView.getHandler(), animStartedListener);
         } else {
             opts = ActivityOptions.makeBasic();
         }
         if (boundsValid) {
-            opts.setBounds(bounds);
+            opts.setBounds(bounds.isEmpty() ? null : bounds);
         }
         final ActivityOptions launchOpts = opts;
         final boolean screenPinningRequested = (animStartedListener == null) && lockToTask;
@@ -710,11 +698,13 @@
     public void onTaskStackFilterTriggered() {
         // Hide the search bar
         if (mSearchBar != null) {
+            int filterDuration = getResources().getInteger(
+                    R.integer.recents_filter_animate_current_views_duration);
             mSearchBar.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.filteringCurrentViewsAnimDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setDuration(filterDuration)
                     .withLayer()
                     .start();
         }
@@ -724,11 +714,13 @@
     public void onTaskStackUnfilterTriggered() {
         // Show the search bar
         if (mSearchBar != null) {
+            int filterDuration = getResources().getInteger(
+                    R.integer.recents_filter_animate_new_views_duration);
             mSearchBar.animate()
                     .alpha(1f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.filteringNewViewsAnimDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setDuration(filterDuration)
                     .withLayer()
                     .start();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
index 0428b48..e04699c1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SwipeHelper.java
@@ -22,13 +22,15 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.TargetApi;
+import android.content.Context;
 import android.os.Build;
 import android.util.DisplayMetrics;
 import android.view.MotionEvent;
 import android.view.VelocityTracker;
 import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.view.animation.LinearInterpolator;
-import com.android.systemui.recents.RecentsConfiguration;
 
 /**
  * This class facilitates swipe to dismiss. It defines an interface to be implemented by the
@@ -46,6 +48,7 @@
     public static final int Y = 1;
 
     private static LinearInterpolator sLinearInterpolator = new LinearInterpolator();
+    private Interpolator mLinearOutSlowInInterpolator;
 
     private float SWIPE_ESCAPE_VELOCITY = 100f; // dp/sec
     private int DEFAULT_ESCAPE_ANIMATION_DURATION = 75; // ms
@@ -74,13 +77,15 @@
     public boolean mAllowSwipeTowardsEnd = true;
     private boolean mRtl;
 
-    public SwipeHelper(int swipeDirection, Callback callback, float densityScale,
+    public SwipeHelper(Context context, int swipeDirection, Callback callback, float densityScale,
             float pagingTouchSlop) {
         mCallback = callback;
         mSwipeDirection = swipeDirection;
         mVelocityTracker = VelocityTracker.obtain();
         mDensityScale = densityScale;
         mPagingTouchSlop = pagingTouchSlop;
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
     }
 
     public void setDensityScale(float densityScale) {
@@ -265,7 +270,7 @@
         ValueAnimator anim = createTranslationAnimation(view, 0);
         int duration = SNAP_ANIM_LEN;
         anim.setDuration(duration);
-        anim.setInterpolator(RecentsConfiguration.getInstance().linearOutSlowInInterpolator);
+        anim.setInterpolator(mLinearOutSlowInInterpolator);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 1086160..7ce50d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -17,13 +17,19 @@
 package com.android.systemui.recents.views;
 
 import android.app.Activity;
+import android.content.Context;
 import android.view.View;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.R;
+import com.android.systemui.recents.RecentsActivity;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
 
+    Context mContext;
     RecentsConfiguration mConfig;
 
     View mStatusBarScrimView;
@@ -34,10 +40,22 @@
     boolean mHasStatusBarScrim;
     boolean mShouldAnimateNavBarScrim;
 
-    public SystemBarScrimViews(Activity activity, RecentsConfiguration config) {
-        mConfig = config;
+    int mNavBarScrimEnterDuration;
+
+    Interpolator mFastOutSlowInInterpolator;
+    Interpolator mQuintOutInterpolator;
+
+    public SystemBarScrimViews(Activity activity) {
+        mContext = activity;
+        mConfig = RecentsConfiguration.getInstance();
         mStatusBarScrimView = activity.findViewById(R.id.status_bar_scrim);
         mNavBarScrimView = activity.findViewById(R.id.nav_bar_scrim);
+        mNavBarScrimEnterDuration = activity.getResources().getInteger(
+                R.integer.recents_nav_bar_scrim_enter_duration);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(activity,
+                        com.android.internal.R.interpolator.fast_out_slow_in);
+        mQuintOutInterpolator = AnimationUtils.loadInterpolator(activity,
+                com.android.internal.R.interpolator.decelerate_quint);
     }
 
     /**
@@ -45,10 +63,11 @@
      * the first draw.
      */
     public void prepareEnterRecentsAnimation() {
-        mHasNavBarScrim = mConfig.hasNavBarScrim();
-        mShouldAnimateNavBarScrim = mConfig.shouldAnimateNavBarScrim();
-        mHasStatusBarScrim = mConfig.hasStatusBarScrim();
-        mShouldAnimateStatusBarScrim = mConfig.shouldAnimateStatusBarScrim();
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        mHasNavBarScrim = launchState.hasNavBarScrim();
+        mShouldAnimateNavBarScrim = launchState.shouldAnimateNavBarScrim();
+        mHasStatusBarScrim = launchState.hasStatusBarScrim();
+        mShouldAnimateStatusBarScrim = launchState.shouldAnimateStatusBarScrim();
 
         mNavBarScrimView.setVisibility(mHasNavBarScrim && !mShouldAnimateNavBarScrim ?
                 View.VISIBLE : View.INVISIBLE);
@@ -60,15 +79,21 @@
      * Starts animating the scrim views when entering Recents.
      */
     public void startEnterRecentsAnimation() {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        int transitionEnterFromAppDelay = mContext.getResources().getInteger(
+                R.integer.recents_enter_from_app_transition_duration);
+        int transitionEnterFromHomeDelay = mContext.getResources().getInteger(
+                R.integer.recents_enter_from_home_transition_duration);
+
         if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
             mStatusBarScrimView.setTranslationY(-mStatusBarScrimView.getMeasuredHeight());
             mStatusBarScrimView.animate()
                     .translationY(0)
-                    .setStartDelay(mConfig.launchedFromHome ?
-                            mConfig.transitionEnterFromHomeDelay :
-                            mConfig.transitionEnterFromAppDelay)
-                    .setDuration(mConfig.navBarScrimEnterDuration)
-                    .setInterpolator(mConfig.quintOutInterpolator)
+                    .setStartDelay(launchState.launchedFromHome ?
+                            transitionEnterFromHomeDelay :
+                            transitionEnterFromAppDelay)
+                    .setDuration(mNavBarScrimEnterDuration)
+                    .setInterpolator(mQuintOutInterpolator)
                     .withStartAction(new Runnable() {
                         @Override
                         public void run() {
@@ -81,11 +106,11 @@
             mNavBarScrimView.setTranslationY(mNavBarScrimView.getMeasuredHeight());
             mNavBarScrimView.animate()
                     .translationY(0)
-                    .setStartDelay(mConfig.launchedFromHome ?
-                            mConfig.transitionEnterFromHomeDelay :
-                            mConfig.transitionEnterFromAppDelay)
-                    .setDuration(mConfig.navBarScrimEnterDuration)
-                    .setInterpolator(mConfig.quintOutInterpolator)
+                    .setStartDelay(launchState.launchedFromHome ?
+                            transitionEnterFromHomeDelay :
+                            transitionEnterFromAppDelay)
+                    .setDuration(mNavBarScrimEnterDuration)
+                    .setInterpolator(mQuintOutInterpolator)
                     .withStartAction(new Runnable() {
                         @Override
                         public void run() {
@@ -101,20 +126,22 @@
      * going home).
      */
     public void startExitRecentsAnimation() {
+        int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                R.integer.recents_task_exit_to_app_duration);
         if (mHasStatusBarScrim && mShouldAnimateStatusBarScrim) {
             mStatusBarScrimView.animate()
                     .translationY(-mStatusBarScrimView.getMeasuredHeight())
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
                     .start();
         }
         if (mHasNavBarScrim && mShouldAnimateNavBarScrim) {
             mNavBarScrimView.animate()
                     .translationY(mNavBarScrimView.getMeasuredHeight())
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
                     .start();
         }
     }
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 8058c5e..b5f29a0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -29,10 +29,10 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.FrameLayout;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.DozeTrigger;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -79,7 +79,6 @@
     ViewPool<TaskView, Task> mViewPool;
     ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<TaskViewTransform>();
     DozeTrigger mUIDozeTrigger;
-    DebugOverlayView mDebugOverlay;
     DismissView mDismissAllButton;
     boolean mDismissAllButtonAnimating;
     int mFocusedTaskIndex = -1;
@@ -118,14 +117,17 @@
         // Set the stack first
         setStack(stack);
         mConfig = RecentsConfiguration.getInstance();
-        mViewPool = new ViewPool<TaskView, Task>(context, this);
+        mViewPool = new ViewPool<>(context, this);
         mInflater = LayoutInflater.from(context);
-        mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(mConfig);
-        mFilterAlgorithm = new TaskStackViewFilterAlgorithm(mConfig, this, mViewPool);
-        mStackScroller = new TaskStackViewScroller(context, mConfig, mLayoutAlgorithm);
+        mLayoutAlgorithm = new TaskStackViewLayoutAlgorithm(context, mConfig);
+        mFilterAlgorithm = new TaskStackViewFilterAlgorithm(this, mViewPool);
+        mStackScroller = new TaskStackViewScroller(context, mLayoutAlgorithm);
         mStackScroller.setCallbacks(this);
-        mTouchHandler = new TaskStackViewTouchHandler(context, this, mConfig, mStackScroller);
-        mUIDozeTrigger = new DozeTrigger(mConfig.taskBarDismissDozeDelaySeconds, new Runnable() {
+        mTouchHandler = new TaskStackViewTouchHandler(context, this, mStackScroller);
+
+        int taskBarDismissDozeDelaySeconds = getResources().getInteger(
+                R.integer.recents_task_bar_dismiss_delay_seconds);
+        mUIDozeTrigger = new DozeTrigger(taskBarDismissDozeDelaySeconds, new Runnable() {
             @Override
             public void run() {
                 // Show the task bar dismiss buttons
@@ -161,11 +163,6 @@
         return mStack;
     }
 
-    /** Sets the debug overlay */
-    public void setDebugOverlay(DebugOverlayView overlay) {
-        mDebugOverlay = overlay;
-    }
-
     /** Updates the list of task views */
     void updateTaskViewsList() {
         mTaskViews.clear();
@@ -334,9 +331,6 @@
             int[] visibleRange = mTmpVisibleRange;
             boolean isValidVisibleRange = updateStackTransforms(mCurrentTaskTransforms, tasks,
                     stackScroll, visibleRange, false);
-            if (mDebugOverlay != null) {
-                mDebugOverlay.setText("vis[" + visibleRange[1] + "-" + visibleRange[0] + "]");
-            }
 
             // Inflate and add the dismiss button if necessary
             if (Constants.DebugFlags.App.EnableDismissAll && mDismissAllButton == null) {
@@ -740,8 +734,9 @@
         int height = MeasureSpec.getSize(heightMeasureSpec);
 
         // Compute our stack/task rects
-        computeRects(width, height, mTaskStackBounds, mConfig.launchedWithAltTab,
-                mConfig.launchedFromHome);
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        computeRects(width, height, mTaskStackBounds, launchState.launchedWithAltTab,
+                launchState.launchedFromHome);
 
         // If this is the first layout, then scroll to the front of the stack and synchronize the
         // stack views immediately to load all the views
@@ -773,9 +768,11 @@
         // Measure the dismiss button
         if (mDismissAllButton != null) {
             int taskRectWidth = mLayoutAlgorithm.mTaskRect.width();
+            int dismissAllButtonHeight = getResources().getDimensionPixelSize(
+                    R.dimen.recents_dismiss_all_button_size);
             mDismissAllButton.measure(
                     MeasureSpec.makeMeasureSpec(taskRectWidth, MeasureSpec.EXACTLY),
-                    MeasureSpec.makeMeasureSpec(mConfig.dismissAllButtonSizePx, MeasureSpec.EXACTLY));
+                    MeasureSpec.makeMeasureSpec(dismissAllButtonHeight, MeasureSpec.EXACTLY));
         }
 
         setMeasuredDimension(width, height);
@@ -856,20 +853,19 @@
 
         // When Alt-Tabbing, focus the previous task (but leave the animation until we finish the
         // enter animation).
-        if (mConfig.launchedWithAltTab) {
-            if (mConfig.launchedFromAppWithThumbnail) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        if (launchState.launchedWithAltTab) {
+            if (launchState.launchedFromAppWithThumbnail) {
                 focusTask(Math.max(0, mStack.getTaskCount() - 2), false,
-                        mConfig.launchedHasConfigurationChanged);
+                        launchState.launchedHasConfigurationChanged);
             } else {
                 focusTask(Math.max(0, mStack.getTaskCount() - 1), false,
-                        mConfig.launchedHasConfigurationChanged);
+                        launchState.launchedHasConfigurationChanged);
             }
         }
 
         // Start dozing
-        if (!mConfig.multiWindowEnabled) {
-            mUIDozeTrigger.startDozing();
-        }
+        mUIDozeTrigger.startDozing();
     }
 
     /** Requests this task stacks to start it's enter-recents animation */
@@ -933,7 +929,9 @@
 
                     // Start the focus animation when alt-tabbing
                     ArrayList<Task> tasks = mStack.getTasks();
-                    if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged &&
+                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                    if (launchState.launchedWithAltTab &&
+                            !launchState.launchedHasConfigurationChanged &&
                             0 <= mFocusedTaskIndex && mFocusedTaskIndex < tasks.size()) {
                         TaskView tv = getChildViewForTask(tasks.get(mFocusedTaskIndex));
                         if (tv != null) {
@@ -1124,7 +1122,8 @@
         }
 
         // Update the min/max scroll and animate other task views into their new positions
-        updateMinMaxScroll(true, mConfig.launchedWithAltTab, mConfig.launchedFromHome);
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        updateMinMaxScroll(true, launchState.launchedWithAltTab, launchState.launchedFromHome);
 
         // Offset the stack by as much as the anchor task would otherwise move back
         if (pullStackForward) {
@@ -1142,7 +1141,8 @@
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
                 frontTv.onTaskBound(newFrontMostTask);
-                frontTv.fadeInActionButton(0, mConfig.taskViewEnterFromAppDuration);
+                frontTv.fadeInActionButton(0, getResources().getInteger(
+                        R.integer.recents_task_enter_from_app_duration));
             }
         }
 
@@ -1291,7 +1291,7 @@
         RecentsTaskLoader.getInstance().loadTaskData(task);
 
         // If the doze trigger has already fired, then update the state for this task view
-        if (mConfig.multiWindowEnabled || mUIDozeTrigger.hasTriggered()) {
+        if (mUIDozeTrigger.hasTriggered()) {
             tv.setNoUserInteractionState();
         }
 
@@ -1393,7 +1393,8 @@
                 if (nextTv != null) {
                     // Focus the next task, and only animate the visible state if we are launched
                     // from Alt-Tab
-                    nextTv.setFocusedTask(mConfig.launchedWithAltTab);
+                    RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+                    nextTv.setFocusedTask(launchState.launchedWithAltTab);
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
index 614ca53..e9f6a46 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewFilterAlgorithm.java
@@ -17,8 +17,8 @@
 package com.android.systemui.recents.views;
 
 import com.android.systemui.recents.Constants;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -27,13 +27,10 @@
 /* The layout logic for a TaskStackView */
 public class TaskStackViewFilterAlgorithm {
 
-    RecentsConfiguration mConfig;
     TaskStackView mStackView;
     ViewPool<TaskView, Task> mViewPool;
 
-    public TaskStackViewFilterAlgorithm(RecentsConfiguration config, TaskStackView stackView,
-                                        ViewPool<TaskView, Task> viewPool) {
-        mConfig = config;
+    public TaskStackViewFilterAlgorithm(TaskStackView stackView, ViewPool<TaskView, Task> viewPool) {
         mStackView = stackView;
         mViewPool = viewPool;
     }
@@ -126,7 +123,8 @@
                 }
             }
         }
-        return mConfig.filteringNewViewsAnimDuration;
+        return mStackView.getResources().getInteger(
+                R.integer.recents_filter_animate_new_views_duration);
     }
 
     /**
@@ -172,7 +170,8 @@
             childViewTransformsOut.put(tv, toTransform);
             offset++;
         }
-        return mConfig.filteringCurrentViewsAnimDuration;
+        return mStackView.getResources().getInteger(
+                R.integer.recents_filter_animate_current_views_duration);
     }
 
 }
\ No newline at end of file
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
index f6df881..7f4c0a5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewLayoutAlgorithm.java
@@ -16,11 +16,13 @@
 
 package com.android.systemui.recents.views;
 
+import android.content.Context;
 import android.graphics.Rect;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -48,6 +50,7 @@
         }
     }
 
+    Context mContext;
     RecentsConfiguration mConfig;
 
     // The various rects that define the stack view
@@ -71,7 +74,8 @@
     static float[] xp;
     static float[] px;
 
-    public TaskStackViewLayoutAlgorithm(RecentsConfiguration config) {
+    public TaskStackViewLayoutAlgorithm(Context context, RecentsConfiguration config) {
+        mContext = context;
         mConfig = config;
 
         // Precompute the path
@@ -87,7 +91,8 @@
         mStackVisibleRect.bottom = mViewRect.bottom;
 
         int widthPadding = (int) (mConfig.taskStackWidthPaddingPct * mStackRect.width());
-        int heightPadding = mConfig.taskStackTopPaddingPx;
+        int heightPadding = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_stack_top_padding);
         mStackRect.inset(widthPadding, heightPadding);
 
         // Compute the task rect
@@ -98,7 +103,8 @@
 
         // Update the affiliation offsets
         float visibleTaskPct = 0.5f;
-        mWithinAffiliationOffset = mConfig.taskBarHeight;
+        mWithinAffiliationOffset = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
         mBetweenAffiliationOffset = (int) (visibleTaskPct * mTaskRect.height());
     }
 
@@ -134,8 +140,10 @@
                         mStackRect.bottom));
         float pDismissAllButtonOffset = 0f;
         if (Constants.DebugFlags.App.EnableDismissAll) {
+            int dismissAllButtonHeight = mContext.getResources().getDimensionPixelSize(
+                    R.dimen.recents_dismiss_all_button_size);
             pDismissAllButtonOffset = pAtBottomOfStackRect -
-                screenYToCurveProgress(mStackVisibleRect.bottom - mConfig.dismissAllButtonSizePx);
+                screenYToCurveProgress(mStackVisibleRect.bottom - dismissAllButtonHeight);
         }
 
         // Update the task offsets
@@ -177,6 +185,8 @@
 
         // Walk backwards in the task stack and count the number of tasks and visible thumbnails
         int taskHeight = mTaskRect.height();
+        int taskBarHeight = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_bar_height);
         int numVisibleTasks = 1;
         int numVisibleThumbnails = 1;
         float progress = mTaskProgressMap.get(tasks.get(tasks.size() - 1).key) - mInitialScrollP;
@@ -192,7 +202,7 @@
                 float scaleAtP = curveProgressToScale(progress);
                 int scaleYOffsetAtP = (int) (((1f - scaleAtP) * taskHeight) / 2);
                 int screenY = curveProgressToScreenY(progress) + scaleYOffsetAtP;
-                boolean hasVisibleThumbnail = (prevScreenY - screenY) > mConfig.taskBarHeight;
+                boolean hasVisibleThumbnail = (prevScreenY - screenY) > taskBarHeight;
                 if (hasVisibleThumbnail) {
                     numVisibleThumbnails++;
                     numVisibleTasks++;
@@ -251,8 +261,8 @@
         }
         float scale = curveProgressToScale(pBounded);
         int scaleYOffset = (int) (((1f - scale) * mTaskRect.height()) / 2);
-        int minZ = mConfig.taskViewTranslationZMinPx;
-        int maxZ = mConfig.taskViewTranslationZMaxPx;
+        int minZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_min);
+        int maxZ = mContext.getResources().getDimensionPixelSize(R.dimen.recents_task_view_z_max);
         transformOut.scale = scale;
         transformOut.translationY = curveProgressToScreenY(pBounded) - mStackVisibleRect.top -
                 scaleYOffset;
@@ -265,11 +275,9 @@
         return transformOut;
     }
 
-    /** Returns the untransformed task view size. */
-    public Rect getUntransformedTaskViewSize() {
-        Rect tvSize = new Rect(mTaskRect);
-        tvSize.offsetTo(0, 0);
-        return tvSize;
+    /** Returns the untransformed task view bounds. */
+    public Rect getUntransformedTaskViewBounds() {
+        return new Rect(mTaskRect);
     }
 
     /** Returns the scroll to such task top = 1f; */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
index fabc86d..f0ae87f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewScroller.java
@@ -21,9 +21,11 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.OverScroller;
-import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
+import com.android.systemui.R;
 
 /* The scrolling logic for a TaskStackView */
 public class TaskStackViewScroller {
@@ -31,7 +33,7 @@
         public void onScrollChanged(float p);
     }
 
-    RecentsConfiguration mConfig;
+    Context mContext;
     TaskStackViewLayoutAlgorithm mLayoutAlgorithm;
     TaskStackViewScrollerCallbacks mCb;
 
@@ -41,10 +43,14 @@
     ObjectAnimator mScrollAnimator;
     float mFinalAnimatedScroll;
 
-    public TaskStackViewScroller(Context context, RecentsConfiguration config, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
-        mConfig = config;
+    Interpolator mLinearOutSlowInInterpolator;
+
+    public TaskStackViewScroller(Context context, TaskStackViewLayoutAlgorithm layoutAlgorithm) {
+        mContext = context;
         mScroller = new OverScroller(context);
         mLayoutAlgorithm = layoutAlgorithm;
+        mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.linear_out_slow_in);
         setStackScroll(getStackScroll());
     }
 
@@ -140,8 +146,9 @@
 
         mFinalAnimatedScroll = newScroll;
         mScrollAnimator = ObjectAnimator.ofFloat(this, "stackScroll", curScroll, newScroll);
-        mScrollAnimator.setDuration(mConfig.taskStackScrollDuration);
-        mScrollAnimator.setInterpolator(mConfig.linearOutSlowInInterpolator);
+        mScrollAnimator.setDuration(mContext.getResources().getInteger(
+                R.integer.recents_animate_task_stack_scroll_duration));
+        mScrollAnimator.setInterpolator(mLinearOutSlowInInterpolator);
         mScrollAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 7d079d9..86eced8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -26,7 +26,7 @@
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.recents.Constants;
 import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.RecentsConfiguration;
+import com.android.systemui.R;
 
 import java.util.List;
 
@@ -34,7 +34,7 @@
 class TaskStackViewTouchHandler implements SwipeHelper.Callback {
     static int INACTIVE_POINTER_ID = -1;
 
-    RecentsConfiguration mConfig;
+    Context mContext;
     TaskStackView mSv;
     TaskStackViewScroller mScroller;
     VelocityTracker mVelocityTracker;
@@ -62,7 +62,8 @@
     boolean mInterceptedBySwipeHelper;
 
     public TaskStackViewTouchHandler(Context context, TaskStackView sv,
-            RecentsConfiguration config, TaskStackViewScroller scroller) {
+            TaskStackViewScroller scroller) {
+        mContext = context;
         ViewConfiguration configuration = ViewConfiguration.get(context);
         mMinimumVelocity = configuration.getScaledMinimumFlingVelocity();
         mMaximumVelocity = configuration.getScaledMaximumFlingVelocity();
@@ -71,10 +72,9 @@
         mWindowTouchSlop = configuration.getScaledWindowTouchSlop();
         mSv = sv;
         mScroller = scroller;
-        mConfig = config;
 
         float densityScale = context.getResources().getDisplayMetrics().density;
-        mSwipeHelper = new SwipeHelper(SwipeHelper.X, this, densityScale, mPagingTouchSlop);
+        mSwipeHelper = new SwipeHelper(context, SwipeHelper.X, this, densityScale, mPagingTouchSlop);
         mSwipeHelper.setMinAlpha(1f);
     }
 
@@ -268,7 +268,8 @@
                     if (Float.compare(overScrollAmount, 0f) != 0) {
                         // Bound the overscroll to a fixed amount, and inversely scale the y-movement
                         // relative to how close we are to the max overscroll
-                        float maxOverScroll = mConfig.taskStackOverscrollPct;
+                        float maxOverScroll = mContext.getResources().getFloat(
+                                R.dimen.recents_stack_overscroll_percentage);
                         deltaP *= (1f - (Math.min(maxOverScroll, overScrollAmount)
                                 / maxOverScroll));
                     }
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 373fe7b..bbbaccf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -20,16 +20,25 @@
 import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
 import android.content.Context;
-import android.graphics.*;
+import android.content.res.Resources;
+import android.graphics.Color;
+import android.graphics.Outline;
+import android.graphics.Paint;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.Rect;
 import android.util.AttributeSet;
-import android.view.accessibility.AccessibilityManager;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.accessibility.AccessibilityManager;
 import android.view.animation.AccelerateInterpolator;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.recents.Constants;
+import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
@@ -75,6 +84,10 @@
     View mActionButtonView;
     TaskViewCallbacks mCb;
 
+    Interpolator mFastOutSlowInInterpolator;
+    Interpolator mFastOutLinearInInterpolator;
+    Interpolator mQuintOutInterpolator;
+
     // Optimizations
     ValueAnimator.AnimatorUpdateListener mUpdateDimListener =
             new ValueAnimator.AnimatorUpdateListener() {
@@ -99,14 +112,22 @@
 
     public TaskView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
+        Resources res = context.getResources();
         mConfig = RecentsConfiguration.getInstance();
-        mMaxDimScale = mConfig.taskStackMaxDim / 255f;
+        mMaxDimScale = res.getInteger(R.integer.recents_max_task_stack_view_dim) / 255f;
         mClipViewInStack = true;
-        mViewBounds = new AnimateableViewBounds(this, mConfig.taskViewRoundedCornerRadiusPx);
+        mViewBounds = new AnimateableViewBounds(this, res.getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius));
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
+        mQuintOutInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.decelerate_quint);
         setTaskProgress(getTaskProgress());
         setDim(getDim());
         if (mConfig.fakeShadows) {
-            setBackground(new FakeShadowDrawable(context.getResources(), mConfig));
+            setBackground(new FakeShadowDrawable(res, mConfig));
         }
         setOutlineProvider(mViewBounds);
     }
@@ -159,6 +180,7 @@
 
         int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
         int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
+        int taskBarHeight = getResources().getDimensionPixelSize(R.dimen.recents_task_bar_height);
 
         // Measure the content
         mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
@@ -166,7 +188,7 @@
 
         // Measure the bar view, and action button
         mHeaderView.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(mConfig.taskBarHeight, MeasureSpec.EXACTLY));
+                MeasureSpec.makeMeasureSpec(taskBarHeight, MeasureSpec.EXACTLY));
         mActionButtonView.measure(
                 MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.AT_MOST),
                 MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.AT_MOST));
@@ -186,7 +208,7 @@
     void updateViewPropertiesToTaskTransform(TaskViewTransform toTransform, int duration,
                                              ValueAnimator.AnimatorUpdateListener updateCallback) {
         // Apply the transform
-        toTransform.applyToTaskView(this, duration, mConfig.fastOutSlowInInterpolator, false,
+        toTransform.applyToTaskView(this, duration, mFastOutSlowInInterpolator, false,
                 !mConfig.fakeShadows, updateCallback);
 
         // Update the task progress
@@ -238,10 +260,11 @@
      * first layout because the actual animation into recents may take a long time. */
     void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask,
                                              boolean occludesLaunchTarget, int offscreenY) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
         int initialDim = getDim();
-        if (mConfig.launchedHasConfigurationChanged) {
+        if (launchState.launchedHasConfigurationChanged) {
             // Just load the views as-is
-        } else if (mConfig.launchedFromAppWithThumbnail) {
+        } else if (launchState.launchedFromAppWithThumbnail) {
             if (isTaskViewLaunchTargetTask) {
                 // Set the dim to 0 so we can animate it in
                 initialDim = 0;
@@ -252,7 +275,7 @@
                 setTranslationY(offscreenY);
             }
 
-        } else if (mConfig.launchedFromHome) {
+        } else if (launchState.launchedFromHome) {
             // Move the task view off screen (below) so we can animate it in
             setTranslationY(offscreenY);
             setTranslationZ(0);
@@ -267,45 +290,59 @@
 
     /** Animates this task view as it enters recents */
     void startEnterRecentsAnimation(final ViewAnimation.TaskViewEnterContext ctx) {
+        RecentsActivityLaunchState launchState = mConfig.getLaunchState();
+        Resources res = mContext.getResources();
         final TaskViewTransform transform = ctx.currentTaskTransform;
+        final int transitionEnterFromAppDelay = res.getInteger(
+                R.integer.recents_enter_from_app_transition_duration);
+        final int transitionEnterFromHomeDelay = res.getInteger(
+                R.integer.recents_enter_from_home_transition_duration);
+        final int taskViewEnterFromAppDuration = res.getInteger(
+                R.integer.recents_task_enter_from_app_duration);
+        final int taskViewEnterFromHomeDuration = res.getInteger(
+                R.integer.recents_task_enter_from_home_duration);
+        final int taskViewEnterFromHomeStaggerDelay = res.getInteger(
+                R.integer.recents_task_enter_from_home_stagger_delay);
+        final int taskViewAffiliateGroupEnterOffset = res.getDimensionPixelSize(
+                R.dimen.recents_task_view_affiliate_group_enter_offset);
         int startDelay = 0;
 
-        if (mConfig.launchedFromAppWithThumbnail) {
+        if (launchState.launchedFromAppWithThumbnail) {
             if (mTask.isLaunchTarget) {
                 // Animate the dim/overlay
                 if (Constants.DebugFlags.App.EnableThumbnailAlphaOnFrontmost) {
                     // Animate the thumbnail alpha before the dim animation (to prevent updating the
                     // hardware layer)
-                    mThumbnailView.startEnterRecentsAnimation(mConfig.transitionEnterFromAppDelay,
+                    mThumbnailView.startEnterRecentsAnimation(transitionEnterFromAppDelay,
                             new Runnable() {
                                 @Override
                                 public void run() {
-                                    animateDimToProgress(0, mConfig.taskViewEnterFromAppDuration,
+                                    animateDimToProgress(0, taskViewEnterFromAppDuration,
                                             ctx.postAnimationTrigger.decrementOnAnimationEnd());
                                 }
                             });
                 } else {
                     // Immediately start the dim animation
-                    animateDimToProgress(mConfig.transitionEnterFromAppDelay,
-                            mConfig.taskViewEnterFromAppDuration,
+                    animateDimToProgress(transitionEnterFromAppDelay,
+                            taskViewEnterFromAppDuration,
                             ctx.postAnimationTrigger.decrementOnAnimationEnd());
                 }
                 ctx.postAnimationTrigger.increment();
 
                 // Animate the action button in
-                fadeInActionButton(mConfig.transitionEnterFromAppDelay,
-                        mConfig.taskViewEnterFromAppDuration);
+                fadeInActionButton(transitionEnterFromAppDelay,
+                        taskViewEnterFromAppDuration);
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
-                    setTranslationY(transform.translationY + mConfig.taskViewAffiliateGroupEnterOffsetPx);
+                    setTranslationY(transform.translationY + taskViewAffiliateGroupEnterOffset);
                     setAlpha(0f);
                     animate().alpha(1f)
                             .translationY(transform.translationY)
-                            .setStartDelay(mConfig.transitionEnterFromAppDelay)
+                            .setStartDelay(transitionEnterFromAppDelay)
                             .setUpdateListener(null)
-                            .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                            .setDuration(mConfig.taskViewEnterFromHomeDuration)
+                            .setInterpolator(mFastOutSlowInInterpolator)
+                            .setDuration(taskViewEnterFromHomeDuration)
                             .withEndAction(new Runnable() {
                                 @Override
                                 public void run() {
@@ -317,13 +354,13 @@
                     ctx.postAnimationTrigger.increment();
                 }
             }
-            startDelay = mConfig.transitionEnterFromAppDelay;
+            startDelay = transitionEnterFromAppDelay;
 
-        } else if (mConfig.launchedFromHome) {
+        } else if (launchState.launchedFromHome) {
             // Animate the tasks up
             int frontIndex = (ctx.currentStackViewCount - ctx.currentStackViewIndex - 1);
-            int delay = mConfig.transitionEnterFromHomeDelay +
-                    frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay;
+            int delay = transitionEnterFromHomeDelay +
+                    frontIndex * taskViewEnterFromHomeStaggerDelay;
 
             setScaleX(transform.scale);
             setScaleY(transform.scale);
@@ -334,9 +371,9 @@
                     .translationY(transform.translationY)
                     .setStartDelay(delay)
                     .setUpdateListener(ctx.updateListener)
-                    .setInterpolator(mConfig.quintOutInterpolator)
-                    .setDuration(mConfig.taskViewEnterFromHomeDuration +
-                            frontIndex * mConfig.taskViewEnterFromHomeStaggerDelay)
+                    .setInterpolator(mQuintOutInterpolator)
+                    .setDuration(taskViewEnterFromHomeDuration +
+                            frontIndex * taskViewEnterFromHomeStaggerDelay)
                     .withEndAction(new Runnable() {
                         @Override
                         public void run() {
@@ -373,12 +410,14 @@
 
     /** Animates this task view as it leaves recents by pressing home. */
     void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
+        int taskViewExitToHomeDuration = getResources().getInteger(
+                R.integer.recents_task_exit_to_home_duration);
         animate()
                 .translationY(ctx.offscreenTranslationY)
                 .setStartDelay(0)
                 .setUpdateListener(null)
-                .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                .setDuration(mConfig.taskViewExitToHomeDuration)
+                .setInterpolator(mFastOutLinearInInterpolator)
+                .setDuration(taskViewExitToHomeDuration)
                 .withEndAction(ctx.postAnimationTrigger.decrementAsRunnable())
                 .start();
         ctx.postAnimationTrigger.increment();
@@ -392,6 +431,11 @@
     /** Animates this task view as it exits recents */
     void startLaunchTaskAnimation(final Runnable postAnimRunnable, boolean isLaunchingTask,
             boolean occludesLaunchTarget, boolean lockToTask) {
+        final int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                R.integer.recents_task_exit_to_app_duration);
+        final int taskViewAffiliateGroupEnterOffset = mContext.getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_affiliate_group_enter_offset);
+
         if (isLaunchingTask) {
             // Animate the thumbnail alpha back into full opacity for the window animation out
             mThumbnailView.startLaunchTaskAnimation(postAnimRunnable);
@@ -399,8 +443,8 @@
             // Animate the dim
             if (mDimAlpha > 0) {
                 ObjectAnimator anim = ObjectAnimator.ofInt(this, "dim", 0);
-                anim.setDuration(mConfig.taskViewExitToAppDuration);
-                anim.setInterpolator(mConfig.fastOutLinearInInterpolator);
+                anim.setDuration(taskViewExitToAppDuration);
+                anim.setInterpolator(mFastOutLinearInInterpolator);
                 anim.start();
             }
 
@@ -414,8 +458,8 @@
             mActionButtonView.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
-                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
                     .start();
         } else {
             // Hide the dismiss button
@@ -424,11 +468,11 @@
             // animate it away first
             if (occludesLaunchTarget) {
                 animate().alpha(0f)
-                    .translationY(getTranslationY() + mConfig.taskViewAffiliateGroupEnterOffsetPx)
+                    .translationY(getTranslationY() + taskViewAffiliateGroupEnterOffset)
                     .setStartDelay(0)
                     .setUpdateListener(null)
-                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
                     .start();
             }
         }
@@ -436,15 +480,20 @@
 
     /** Animates the deletion of this task view */
     void startDeleteTaskAnimation(final Runnable r, int delay) {
+        int taskViewRemoveAnimDuration = getResources().getInteger(
+                R.integer.recents_animate_task_view_remove_duration);
+        int taskViewRemoveAnimTranslationXPx = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_remove_anim_translation_x);
+
         // Disabling clipping with the stack while the view is animating away
         setClipViewInStack(false);
 
-        animate().translationX(mConfig.taskViewRemoveAnimTranslationXPx)
+        animate().translationX(taskViewRemoveAnimTranslationXPx)
             .alpha(0f)
             .setStartDelay(delay)
             .setUpdateListener(null)
-            .setInterpolator(mConfig.fastOutSlowInInterpolator)
-            .setDuration(mConfig.taskViewRemoveAnimDuration)
+            .setInterpolator(mFastOutSlowInInterpolator)
+            .setDuration(taskViewRemoveAnimDuration)
             .withEndAction(new Runnable() {
                 @Override
                 public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 3e9410e..f68dd64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -26,19 +26,21 @@
 import android.content.res.ColorStateList;
 import android.graphics.Canvas;
 import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.Drawable;
-import android.graphics.drawable.GradientDrawable;
-import android.graphics.drawable.RippleDrawable;
 import android.graphics.Outline;
 import android.graphics.Paint;
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
+import android.graphics.drawable.GradientDrawable;
+import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewOutlineProvider;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
 import android.widget.TextView;
@@ -67,6 +69,8 @@
     boolean mCurrentPrimaryColorIsDark;
     int mCurrentPrimaryColor;
     int mBackgroundColor;
+    int mCornerRadius;
+    int mHighlightHeight;
     Drawable mLightDismissDrawable;
     Drawable mDarkDismissDrawable;
     RippleDrawable mBackground;
@@ -81,6 +85,9 @@
     Paint mDimLayerPaint = new Paint();
     PorterDuffColorFilter mDimColorFilter = new PorterDuffColorFilter(0, PorterDuff.Mode.SRC_ATOP);
 
+    Interpolator mFastOutSlowInInterpolator;
+    Interpolator mFastOutLinearInInterpolator;
+
     boolean mLayersDisabled;
 
     public TaskViewHeader(Context context) {
@@ -113,13 +120,21 @@
         mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
         mDismissContentDescription =
                 context.getString(R.string.accessibility_recents_item_will_be_dismissed);
+        mCornerRadius = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
+        mHighlightHeight = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_highlight);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
+        mFastOutLinearInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_linear_in);
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
             sHighlightPaint = new Paint();
             sHighlightPaint.setStyle(Paint.Style.STROKE);
-            sHighlightPaint.setStrokeWidth(mConfig.taskViewHighlightPx);
-            sHighlightPaint.setColor(mConfig.taskBarViewHighlightColor);
+            sHighlightPaint.setStrokeWidth(mHighlightHeight);
+            sHighlightPaint.setColor(context.getColor(R.color.recents_task_bar_highlight_color));
             sHighlightPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD));
             sHighlightPaint.setAntiAlias(true);
         }
@@ -154,8 +169,8 @@
     @Override
     protected void onDraw(Canvas canvas) {
         // Draw the highlight at the top edge (but put the bottom edge just out of view)
-        float offset = (float) Math.ceil(mConfig.taskViewHighlightPx / 2f);
-        float radius = mConfig.taskViewRoundedCornerRadiusPx;
+        float offset = (float) Math.ceil(mHighlightHeight / 2f);
+        float radius = mCornerRadius;
         int count = canvas.save(Canvas.CLIP_SAVE_FLAG);
         canvas.clipRect(0, 0, getMeasuredWidth(), getMeasuredHeight());
         canvas.drawRoundRect(-offset, 0f, (float) getMeasuredWidth() + offset,
@@ -207,10 +222,15 @@
             mBackgroundColorDrawable.setColor(t.colorPrimary);
             mBackgroundColor = t.colorPrimary;
         }
+
+        int taskBarViewLightTextColor = getResources().getColor(
+                R.color.recents_task_bar_light_text_color);
+        int taskBarViewDarkTextColor = getResources().getColor(
+                R.color.recents_task_bar_dark_text_color);
         mCurrentPrimaryColor = t.colorPrimary;
         mCurrentPrimaryColorIsDark = t.useLightOnPrimaryColor;
         mActivityDescription.setTextColor(t.useLightOnPrimaryColor ?
-                mConfig.taskBarViewLightTextColor : mConfig.taskBarViewDarkTextColor);
+                taskBarViewLightTextColor : taskBarViewDarkTextColor);
         mDismissButton.setImageDrawable(t.useLightOnPrimaryColor ?
                 mLightDismissDrawable : mDarkDismissDrawable);
         mDismissButton.setContentDescription(String.format(mDismissContentDescription,
@@ -262,12 +282,14 @@
     /** Animates this task bar dismiss button when launching a task. */
     void startLaunchTaskDismissAnimation() {
         if (mDismissButton.getVisibility() == View.VISIBLE) {
+            int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                    R.integer.recents_task_exit_to_app_duration);
             mDismissButton.animate().cancel();
             mDismissButton.animate()
                     .alpha(0f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutSlowInInterpolator)
-                    .setDuration(mConfig.taskViewExitToAppDuration)
+                    .setInterpolator(mFastOutSlowInInterpolator)
+                    .setDuration(taskViewExitToAppDuration)
                     .start();
         }
     }
@@ -280,8 +302,9 @@
             mDismissButton.animate()
                     .alpha(1f)
                     .setStartDelay(0)
-                    .setInterpolator(mConfig.fastOutLinearInInterpolator)
-                    .setDuration(mConfig.taskViewEnterFromAppDuration)
+                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .setDuration(getResources().getInteger(
+                            R.integer.recents_task_enter_from_app_duration))
                     .start();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 117a7d3..6c83bee 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -32,9 +32,11 @@
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.view.View;
-import com.android.systemui.recents.RecentsConfiguration;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
+import com.android.systemui.R;
 
 
 /**
@@ -43,9 +45,8 @@
  */
 public class TaskViewThumbnail extends View {
 
-    RecentsConfiguration mConfig;
-
     // Drawing
+    int mCornerRadius;
     float mDimAlpha;
     Matrix mScaleMatrix = new Matrix();
     Paint mDrawPaint = new Paint();
@@ -54,6 +55,8 @@
     BitmapShader mBitmapShader;
     LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
 
+    Interpolator mFastOutSlowInInterpolator;
+
     // Thumbnail alpha
     float mThumbnailAlpha;
     ValueAnimator mThumbnailAlphaAnimator;
@@ -89,15 +92,18 @@
 
     public TaskViewThumbnail(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
-        mConfig = RecentsConfiguration.getInstance();
         mDrawPaint.setColorFilter(mLightingColorFilter);
         mDrawPaint.setFilterBitmap(true);
         mDrawPaint.setAntiAlias(true);
+        mCornerRadius = getResources().getDimensionPixelSize(
+                R.dimen.recents_task_view_rounded_corners_radius);
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
+                com.android.internal.R.interpolator.fast_out_slow_in);
     }
 
     @Override
     protected void onFinishInflate() {
-        mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
+        mThumbnailAlpha = getResources().getFloat(R.dimen.recents_task_view_thumbnail_alpha);
         updateThumbnailPaintFilter();
     }
 
@@ -117,8 +123,8 @@
         }
         // Draw the thumbnail with the rounded corners
         canvas.drawRoundRect(0, 0, getWidth(), getHeight(),
-                mConfig.taskViewRoundedCornerRadiusPx,
-                mConfig.taskViewRoundedCornerRadiusPx, mDrawPaint);
+                mCornerRadius,
+                mCornerRadius, mDrawPaint);
     }
 
     /** Sets the thumbnail to a given bitmap. */
@@ -215,8 +221,10 @@
                 startFadeAnimation(1f, 0, 150, null);
             }
         } else {
-            if (Float.compare(getAlpha(), mConfig.taskViewThumbnailAlpha) != 0) {
-                startFadeAnimation(mConfig.taskViewThumbnailAlpha, 0, 150, null);
+            float taskViewThumbnailAlpha = getResources().getFloat(
+                    R.dimen.recents_task_view_thumbnail_alpha);
+            if (Float.compare(getAlpha(), taskViewThumbnailAlpha) != 0) {
+                startFadeAnimation(taskViewThumbnailAlpha, 0, 150, null);
             }
         }
     }
@@ -229,20 +237,26 @@
         if (isTaskViewLaunchTargetTask) {
             mThumbnailAlpha = 1f;
         } else {
-            mThumbnailAlpha = mConfig.taskViewThumbnailAlpha;
+            mThumbnailAlpha = getResources().getFloat(
+                    R.dimen.recents_task_view_thumbnail_alpha);
         }
         updateThumbnailPaintFilter();
     }
 
     /** Animates this task thumbnail as it enters Recents. */
     void startEnterRecentsAnimation(int delay, Runnable postAnimRunnable) {
-        startFadeAnimation(mConfig.taskViewThumbnailAlpha, delay,
-                mConfig.taskViewEnterFromAppDuration, postAnimRunnable);
+        float taskViewThumbnailAlpha = getResources().getFloat(
+                R.dimen.recents_task_view_thumbnail_alpha);
+        startFadeAnimation(taskViewThumbnailAlpha, delay,
+                getResources().getInteger(R.integer.recents_task_enter_from_app_duration),
+                postAnimRunnable);
     }
 
     /** Animates this task thumbnail as it exits Recents. */
     void startLaunchTaskAnimation(Runnable postAnimRunnable) {
-        startFadeAnimation(1f, 0, mConfig.taskViewExitToAppDuration, postAnimRunnable);
+        int taskViewExitToAppDuration = mContext.getResources().getInteger(
+                R.integer.recents_task_exit_to_app_duration);
+        startFadeAnimation(1f, 0, taskViewExitToAppDuration, postAnimRunnable);
     }
 
     /** Starts a new thumbnail alpha animation. */
@@ -251,7 +265,7 @@
         mThumbnailAlphaAnimator = ValueAnimator.ofFloat(mThumbnailAlpha, finalAlpha);
         mThumbnailAlphaAnimator.setStartDelay(delay);
         mThumbnailAlphaAnimator.setDuration(duration);
-        mThumbnailAlphaAnimator.setInterpolator(mConfig.fastOutSlowInInterpolator);
+        mThumbnailAlphaAnimator.setInterpolator(mFastOutSlowInInterpolator);
         mThumbnailAlphaAnimator.addUpdateListener(mThumbnailAlphaUpdateListener);
         if (postAnimRunnable != null) {
             mThumbnailAlphaAnimator.addListener(new AnimatorListenerAdapter() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index b01a2a8..10d4a96 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -112,7 +112,7 @@
         public void appTransitionStarting(long startTime, long duration);
         public void showAssistDisclosure();
         public void startAssist(Bundle args);
-        public void onCameraLaunchGestureDetected();
+        public void onCameraLaunchGestureDetected(int source);
     }
 
     public CommandQueue(Callbacks callbacks, StatusBarIconList list) {
@@ -306,10 +306,10 @@
     }
 
     @Override
-    public void onCameraLaunchGestureDetected() {
+    public void onCameraLaunchGestureDetected(int source) {
         synchronized (mList) {
             mHandler.removeMessages(MSG_CAMERA_LAUNCH_GESTURE);
-            mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE).sendToTarget();
+            mHandler.obtainMessage(MSG_CAMERA_LAUNCH_GESTURE, source, 0).sendToTarget();
         }
     }
 
@@ -415,7 +415,7 @@
                     mCallbacks.startAssist((Bundle) msg.obj);
                     break;
                 case MSG_CAMERA_LAUNCH_GESTURE:
-                    mCallbacks.onCameraLaunchGestureDetected();
+                    mCallbacks.onCameraLaunchGestureDetected(msg.arg1);
                     break;
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
index d912795..687f6c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/DragDownHelper.java
@@ -130,7 +130,7 @@
                 }
                 return true;
             case MotionEvent.ACTION_UP:
-                if (mDraggedFarEnough && mDragDownCallback.onDraggedDown(mStartingChild,
+                if (!isFalseTouch() && mDragDownCallback.onDraggedDown(mStartingChild,
                         (int) (y - mInitialTouchY))) {
                     if (mStartingChild == null) {
                         mDragDownCallback.setEmptyDragAmount(0f);
@@ -148,6 +148,13 @@
         return false;
     }
 
+    private boolean isFalseTouch() {
+        if (mFalsingManager.isClassiferEnabled()) {
+            return mFalsingManager.isFalseTouch();
+        }
+        return !mDraggedFarEnough;
+    }
+
     private void captureStartingChild(float x, float y) {
         if (mStartingChild == null) {
             mStartingChild = findView(x, y);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index ac4dee2..5e6fdd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -187,32 +187,41 @@
         }
 
         // Try fetching charging time from battery stats.
+        long chargingTimeRemaining = 0;
         try {
-            long chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
-            if (chargingTimeRemaining > 0) {
-                String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
-                        mContext, chargingTimeRemaining);
-                return mContext.getResources().getString(
-                        R.string.keyguard_indication_charging_time, chargingTimeFormatted);
-            }
+            chargingTimeRemaining = mBatteryInfo.computeChargeTimeRemaining();
+
         } catch (RemoteException e) {
             Log.e(TAG, "Error calling IBatteryStats: ", e);
         }
+        final boolean hasChargingTime = chargingTimeRemaining > 0;
 
-        // Fall back to simple charging label.
         int chargingId;
         switch (mChargingSpeed) {
             case KeyguardUpdateMonitor.BatteryStatus.CHARGING_FAST:
-                chargingId = R.string.keyguard_plugged_in_charging_fast;
+                chargingId = hasChargingTime
+                        ? R.string.keyguard_indication_charging_time_fast_if_translated
+                        : R.string.keyguard_plugged_in_charging_fast;
                 break;
             case KeyguardUpdateMonitor.BatteryStatus.CHARGING_SLOWLY:
-                chargingId = R.string.keyguard_plugged_in_charging_slowly;
+                chargingId = hasChargingTime
+                        ? R.string.keyguard_indication_charging_time_slowly_if_translated
+                        : R.string.keyguard_plugged_in_charging_slowly;
                 break;
             default:
-                chargingId = R.string.keyguard_plugged_in;
+                chargingId = hasChargingTime
+                        ? R.string.keyguard_indication_charging_time
+                        : R.string.keyguard_plugged_in;
                 break;
         }
-        return mContext.getResources().getString(chargingId);
+
+        if (hasChargingTime) {
+            String chargingTimeFormatted = Formatter.formatShortElapsedTimeRoundingUpToMinutes(
+                    mContext, chargingTimeRemaining);
+            return mContext.getResources().getString(chargingId, chargingTimeFormatted);
+        } else {
+            return mContext.getResources().getString(chargingId);
+        }
     }
 
     KeyguardUpdateMonitorCallback mUpdateMonitor = new KeyguardUpdateMonitorCallback() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
index 60ebfdf..41adeb5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardAffordanceHelper.java
@@ -28,6 +28,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
+import com.android.systemui.classifier.FalsingManager;
 import com.android.systemui.statusbar.FlingAnimationUtils;
 import com.android.systemui.statusbar.KeyguardAffordanceView;
 
@@ -62,6 +63,7 @@
     private Interpolator mAppearInterpolator;
     private Interpolator mDisappearInterpolator;
     private Animator mSwipeAnimator;
+    private FalsingManager mFalsingManager;
     private int mMinBackgroundRadius;
     private boolean mMotionCancelled;
     private int mTouchTargetSize;
@@ -109,6 +111,7 @@
                 android.R.interpolator.linear_out_slow_in);
         mDisappearInterpolator = AnimationUtils.loadInterpolator(mContext,
                 android.R.interpolator.fast_out_linear_in);
+        mFalsingManager = FalsingManager.getInstance(mContext);
     }
 
     private void initIcons() {
@@ -322,7 +325,12 @@
         float vel = getCurrentVelocity(lastX, lastY);
 
         // We snap back if the current translation is not far enough
-        boolean snapBack = isBelowFalsingThreshold();
+        boolean snapBack;
+        if (mFalsingManager.isFalseTouch()) {
+            snapBack = mFalsingManager.isFalseTouch();
+        } else {
+            snapBack = isBelowFalsingThreshold();
+        }
 
         // or if the velocity is in the opposite direction.
         boolean velIsInWrongDirection = vel * mTranslation < 0;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
index 012dc9c..14176a6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
@@ -77,6 +77,13 @@
 
     final static String TAG = "PhoneStatusBar/KeyguardBottomAreaView";
 
+    public static final String CAMERA_LAUNCH_SOURCE_AFFORDANCE = "lockscreen_affordance";
+    public static final String CAMERA_LAUNCH_SOURCE_WIGGLE = "wiggle_gesture";
+    public static final String CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP = "power_double_tap";
+
+    public static final String EXTRA_CAMERA_LAUNCH_SOURCE
+            = "com.android.systemui.camera_launch_source";
+
     private static final Intent SECURE_CAMERA_INTENT =
             new Intent(MediaStore.INTENT_ACTION_STILL_IMAGE_CAMERA_SECURE)
                     .addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
@@ -170,7 +177,7 @@
                             CommandQueue.FLAG_EXCLUDE_RECENTS_PANEL, true /* force */);
                     return true;
                 } else if (host == mCameraImageView) {
-                    launchCamera();
+                    launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
                     return true;
                 } else if (host == mLeftAffordanceView) {
                     launchLeftAffordance();
@@ -349,7 +356,7 @@
     @Override
     public void onClick(View v) {
         if (v == mCameraImageView) {
-            launchCamera();
+            launchCamera(CAMERA_LAUNCH_SOURCE_AFFORDANCE);
         } else if (v == mLeftAffordanceView) {
             launchLeftAffordance();
         } if (v == mLockIcon) {
@@ -417,8 +424,9 @@
         }
     }
 
-    public void launchCamera() {
+    public void launchCamera(String source) {
         final Intent intent = getCameraIntent();
+        intent.putExtra(EXTRA_CAMERA_LAUNCH_SOURCE, source);
         boolean wouldLaunchResolverActivity = PreviewInflater.wouldLaunchResolverActivity(
                 mContext, intent, KeyguardUpdateMonitor.getCurrentUser());
         if (intent == SECURE_CAMERA_INTENT && !wouldLaunchResolverActivity) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index e70d146..71267cd 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -81,7 +81,7 @@
     }
 
     private void registerListener() {
-        if (UserSwitcherController.isUserSwitcherAvailable(mUserManager) && mUserListener == null) {
+        if (mUserManager.isUserSwitcherEnabled() && mUserListener == null) {
 
             final UserSwitcherController controller = mUserSwitcherController;
             if (controller != null) {
@@ -103,7 +103,7 @@
 
     @Override
     public void onClick(View v) {
-        if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
+        if (mUserManager.isUserSwitcherEnabled()) {
             if (mKeyguardMode) {
                 if (mKeyguardUserSwitcher != null) {
                     mKeyguardUserSwitcher.show(true /* animate */);
@@ -135,14 +135,14 @@
 
     private void refreshContentDescription() {
         String currentUser = null;
-        if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)
+        if (mUserManager.isUserSwitcherEnabled()
                 && mUserSwitcherController != null) {
             currentUser = mUserSwitcherController.getCurrentUserName(mContext);
         }
 
         String text = null;
         if (isClickable()) {
-            if (UserSwitcherController.isUserSwitcherAvailable(mUserManager)) {
+            if (mUserManager.isUserSwitcherEnabled()) {
                 if (TextUtils.isEmpty(currentUser)) {
                     text = mContext.getString(R.string.accessibility_multi_user_switch_switcher);
                 } else {
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 980527b..08353cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -22,6 +22,7 @@
 import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.app.ActivityManager;
+import android.app.StatusBarManager;
 import android.content.Context;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
@@ -204,6 +205,7 @@
     private boolean mHeadsUpAnimatingAway;
     private boolean mLaunchingAffordance;
     private FalsingManager mFalsingManager;
+    private String mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
 
     private Runnable mHeadsUpExistenceChangedRunnable = new Runnable() {
         @Override
@@ -480,6 +482,7 @@
         mUnlockIconActive = false;
         if (!mLaunchingAffordance) {
             mAfforanceHelper.reset(false);
+            mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
         }
         closeQs();
         mStatusBar.dismissPopups();
@@ -692,7 +695,7 @@
     }
 
     private boolean flingExpandsQs(float vel) {
-        if (isBelowFalsingThreshold()) {
+        if (isFalseTouch()) {
             return false;
         }
         if (Math.abs(vel) < mFlingAnimationUtils.getMinVelocityPxPerSecond()) {
@@ -702,8 +705,14 @@
         }
     }
 
-    private boolean isBelowFalsingThreshold() {
-        return !mQsTouchAboveFalsingThreshold && mStatusBarState == StatusBarState.KEYGUARD;
+    private boolean isFalseTouch() {
+        if (mStatusBarState != StatusBarState.KEYGUARD) {
+            return false;
+        }
+        if (mFalsingManager.isClassiferEnabled()) {
+            return mFalsingManager.isFalseTouch();
+        }
+        return !mQsTouchAboveFalsingThreshold;
     }
 
     private float getQsExpansionFraction() {
@@ -1428,7 +1437,7 @@
             }
             return;
         }
-        boolean belowFalsingThreshold = isBelowFalsingThreshold();
+        boolean belowFalsingThreshold = isFalseTouch();
         if (belowFalsingThreshold) {
             vel = 0;
         }
@@ -1965,20 +1974,23 @@
                 mKeyguardBottomArea.launchLeftAffordance();
             }
         } else {
-            EventLogTags.writeSysuiLockscreenGesture(
-                    EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA, lengthDp, velocityDp);
-
+            if (KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE.equals(
+                    mLastCameraLaunchSource)) {
+                EventLogTags.writeSysuiLockscreenGesture(
+                        EventLogConstants.SYSUI_LOCKSCREEN_GESTURE_SWIPE_CAMERA,
+                        lengthDp, velocityDp);
+            }
             mFalsingManager.onCameraOn();
             if (mFalsingManager.shouldEnforceBouncer()) {
                 mStatusBar.executeRunnableDismissingKeyguard(new Runnable() {
                     @Override
                     public void run() {
-                        mKeyguardBottomArea.launchCamera();
+                        mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
                     }
                 }, null, true /* dismissShade */, false /* afterKeyguardGone */);
             }
             else {
-                mKeyguardBottomArea.launchCamera();
+                mKeyguardBottomArea.launchCamera(mLastCameraLaunchSource);
             }
         }
         mStatusBar.startLaunchTransitionTimeout();
@@ -2419,7 +2431,17 @@
         return !mDozing;
     }
 
-    public void launchCamera(boolean animate) {
+    public void launchCamera(boolean animate, int source) {
+        if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP) {
+            mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP;
+        } else if (source == StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE) {
+            mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_WIGGLE;
+        } else {
+
+            // Default.
+            mLastCameraLaunchSource = KeyguardBottomAreaView.CAMERA_LAUNCH_SOURCE_AFFORDANCE;
+        }
+
         // If we are launching it when we are occluded already we don't want it to animate,
         // nor setting these flags, since the occluded state doesn't change anymore, hence it's
         // never reset.
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 13d0e1e..bd16257 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PanelView.java
@@ -610,8 +610,8 @@
         if (!mStatusBar.isFalsingThresholdNeeded()) {
             return false;
         }
-        if (mFalsingManager.isFalseTouch(Classifier.UNLOCK)) {
-            return true;
+        if (mFalsingManager.isClassiferEnabled()) {
+            return mFalsingManager.isFalseTouch();
         }
         if (!mTouchAboveFalsingThreshold) {
             return true;
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 151fa3c..37edc28 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -492,6 +492,7 @@
     private ExpandableNotificationRow mDraggedDownRow;
     private boolean mLaunchCameraOnScreenTurningOn;
     private boolean mLaunchCameraOnFinishedGoingToSleep;
+    private int mLastCameraLaunchSource;
     private PowerManager.WakeLock mGestureWakeLock;
     private Vibrator mVibrator;
 
@@ -881,7 +882,7 @@
         mKeyguardBottomArea.setAccessibilityController(mAccessibilityController);
         mNextAlarmController = new NextAlarmController(mContext);
         mKeyguardMonitor = new KeyguardMonitor(mContext);
-        if (UserSwitcherController.isUserSwitcherAvailable(UserManager.get(mContext))) {
+        if (UserManager.get(mContext).isUserSwitcherEnabled()) {
             mUserSwitcherController = new UserSwitcherController(mContext, mKeyguardMonitor,
                     mHandler);
             if (mUserSwitcherController.useFullscreenUserSwitcher()) {
@@ -903,8 +904,8 @@
                     mBluetoothController, mLocationController, mRotationLockController,
                     mNetworkController, mZenModeController, mHotspotController,
                     mCastController, mFlashlightController,
-                    mUserSwitcherController, mKeyguardMonitor,
-                    mSecurityController);
+                    mUserSwitcherController, mUserInfoController, mKeyguardMonitor,
+                    mSecurityController, mBatteryController);
             mQSPanel.setHost(qsh);
             mQSPanel.setTiles(qsh.getTiles());
             mBrightnessMirrorController = new BrightnessMirrorController(mStatusBarWindow);
@@ -3000,6 +3001,10 @@
         dismissKeyguardThenExecute(action, null /* cancelRunnable */, afterKeyguardGone);
     }
 
+    public void dismissKeyguard() {
+        mStatusBarKeyguardViewManager.dismiss();
+    }
+
     private void dismissKeyguardThenExecute(OnDismissAction action, Runnable cancelAction,
             boolean afterKeyguardGone) {
         if (mStatusBarKeyguardViewManager.isShowing()) {
@@ -3992,7 +3997,7 @@
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    onCameraLaunchGestureDetected();
+                    onCameraLaunchGestureDetected(mLastCameraLaunchSource);
                 }
             });
         }
@@ -4010,7 +4015,7 @@
         mFalsingManager.onScreenTurningOn();
         mNotificationPanel.onScreenTurningOn();
         if (mLaunchCameraOnScreenTurningOn) {
-            mNotificationPanel.launchCamera(false);
+            mNotificationPanel.launchCamera(false, mLastCameraLaunchSource);
             mLaunchCameraOnScreenTurningOn = false;
         }
     }
@@ -4175,7 +4180,8 @@
     }
 
     @Override
-    public void onCameraLaunchGestureDetected() {
+    public void onCameraLaunchGestureDetected(int source) {
+        mLastCameraLaunchSource = source;
         if (mStartedGoingToSleep) {
             mLaunchCameraOnFinishedGoingToSleep = true;
             return;
@@ -4201,7 +4207,7 @@
                 mGestureWakeLock.acquire(LAUNCH_TRANSITION_TIMEOUT_MS + 1000L);
             }
             if (mScreenTurningOn || mStatusBarKeyguardViewManager.isScreenTurnedOn()) {
-                mNotificationPanel.launchCamera(mDeviceInteractive /* animate */);
+                mNotificationPanel.launchCamera(mDeviceInteractive /* animate */, source);
             } else {
                 // We need to defer the camera launch until the screen comes on, since otherwise
                 // we will dismiss us too early since we are waiting on an activity to be drawn and
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index 385c5d5..6ec9494 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -26,34 +26,8 @@
 
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.tiles.AirplaneModeTile;
-import com.android.systemui.qs.tiles.BluetoothTile;
-import com.android.systemui.qs.tiles.CastTile;
-import com.android.systemui.qs.tiles.CellularTile;
-import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.DndTile;
-import com.android.systemui.qs.tiles.FlashlightTile;
-import com.android.systemui.qs.tiles.HotspotTile;
-import com.android.systemui.qs.tiles.IntentTile;
-import com.android.systemui.qs.tiles.LocationTile;
-import com.android.systemui.qs.tiles.QAirplaneTile;
-import com.android.systemui.qs.tiles.QBluetoothTile;
-import com.android.systemui.qs.tiles.QFlashlightTile;
-import com.android.systemui.qs.tiles.QRotationLockTile;
-import com.android.systemui.qs.tiles.QWifiTile;
-import com.android.systemui.qs.tiles.RotationLockTile;
-import com.android.systemui.qs.tiles.WifiTile;
-import com.android.systemui.statusbar.policy.BluetoothController;
-import com.android.systemui.statusbar.policy.CastController;
-import com.android.systemui.statusbar.policy.FlashlightController;
-import com.android.systemui.statusbar.policy.HotspotController;
-import com.android.systemui.statusbar.policy.KeyguardMonitor;
-import com.android.systemui.statusbar.policy.LocationController;
-import com.android.systemui.statusbar.policy.NetworkController;
-import com.android.systemui.statusbar.policy.RotationLockController;
-import com.android.systemui.statusbar.policy.SecurityController;
-import com.android.systemui.statusbar.policy.UserSwitcherController;
-import com.android.systemui.statusbar.policy.ZenModeController;
+import com.android.systemui.qs.tiles.*;
+import com.android.systemui.statusbar.policy.*;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -85,8 +59,10 @@
     private final Looper mLooper;
     private final FlashlightController mFlashlight;
     private final UserSwitcherController mUserSwitcherController;
+    private final UserInfoController mUserInfoController;
     private final KeyguardMonitor mKeyguard;
     private final SecurityController mSecurity;
+    private final BatteryController mBattery;
 
     private Callback mCallback;
 
@@ -95,8 +71,8 @@
             RotationLockController rotation, NetworkController network,
             ZenModeController zen, HotspotController hotspot,
             CastController cast, FlashlightController flashlight,
-            UserSwitcherController userSwitcher, KeyguardMonitor keyguard,
-            SecurityController security) {
+            UserSwitcherController userSwitcher, UserInfoController userInfo, KeyguardMonitor keyguard,
+            SecurityController security, BatteryController battery) {
         mContext = context;
         mStatusBar = statusBar;
         mBluetooth = bluetooth;
@@ -108,8 +84,10 @@
         mCast = cast;
         mFlashlight = flashlight;
         mUserSwitcherController = userSwitcher;
+        mUserInfoController = userInfo;
         mKeyguard = keyguard;
         mSecurity = security;
+        mBattery = battery;
 
         final HandlerThread ht = new HandlerThread(QSTileHost.class.getSimpleName(),
                 Process.THREAD_PRIORITY_BACKGROUND);
@@ -203,10 +181,21 @@
         return mKeyguard;
     }
 
+    @Override
     public UserSwitcherController getUserSwitcherController() {
         return mUserSwitcherController;
     }
 
+    @Override
+    public UserInfoController getUserInfoController() {
+        return mUserInfoController;
+    }
+
+    @Override
+    public BatteryController getBatteryController() {
+        return mBattery;
+    }
+
     public SecurityController getSecurityController() {
         return mSecurity;
     }
@@ -259,6 +248,8 @@
         else if (tileSpec.equals("location")) return new LocationTile(this);
         else if (tileSpec.equals("cast")) return new CastTile(this);
         else if (tileSpec.equals("hotspot")) return new HotspotTile(this);
+        else if (tileSpec.equals("user")) return new UserTile(this);
+        else if (tileSpec.equals("battery")) return new BatteryTile(this);
         // Detail only versions of wifi and bluetooth.
         else if (tileSpec.equals("dwifi")) return new WifiTile(this, true);
         else if (tileSpec.equals("dbt")) return new BluetoothTile(this, true);
@@ -268,6 +259,7 @@
         else if (tileSpec.equals("qairplane")) return new QAirplaneTile(this);
         else if (tileSpec.equals("qrotation")) return new QRotationLockTile(this);
         else if (tileSpec.equals("qflashlight")) return new QFlashlightTile(this);
+        else if (tileSpec.equals("qlock")) return new QLockTile(this);
         // Intent tiles.
         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
         else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 394ff3f..05f6e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -466,7 +466,7 @@
 
         KeyguardUpdateMonitor updateMonitor = KeyguardUpdateMonitor.getInstance(mContext);
         if ((showing && !occluded) != (mLastShowing && !mLastOccluded) || mFirstUpdate) {
-            updateMonitor.sendKeyguardVisibilityChanged(showing && !occluded);
+            updateMonitor.onKeyguardVisibilityChanged(showing && !occluded);
         }
         if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
             updateMonitor.sendKeyguardBouncerChanged(bouncerShowing);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
index d1b69ab..5071df0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/BatteryController.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.os.BatteryManager;
+import android.os.Handler;
 import android.os.PowerManager;
 import android.util.Log;
 
@@ -30,24 +31,31 @@
 
 public class BatteryController extends BroadcastReceiver {
     private static final String TAG = "BatteryController";
+
+    public static final String ACTION_LEVEL_TEST = "com.android.systemui.BATTERY_LEVEL_TEST";
+
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
     private final ArrayList<BatteryStateChangeCallback> mChangeCallbacks = new ArrayList<>();
     private final PowerManager mPowerManager;
+    private final Handler mHandler;
 
     private int mLevel;
     private boolean mPluggedIn;
     private boolean mCharging;
     private boolean mCharged;
     private boolean mPowerSave;
+    private boolean mTestmode = false;
 
     public BatteryController(Context context) {
+        mHandler = new Handler();
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
 
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_BATTERY_CHANGED);
         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGED);
         filter.addAction(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING);
+        filter.addAction(ACTION_LEVEL_TEST);
         context.registerReceiver(this, filter);
 
         updatePowerSave();
@@ -71,9 +79,10 @@
         mChangeCallbacks.remove(cb);
     }
 
-    public void onReceive(Context context, Intent intent) {
+    public void onReceive(final Context context, Intent intent) {
         final String action = intent.getAction();
         if (action.equals(Intent.ACTION_BATTERY_CHANGED)) {
+            if (mTestmode && !intent.getBooleanExtra("testmode", false)) return;
             mLevel = (int)(100f
                     * intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0)
                     / intent.getIntExtra(BatteryManager.EXTRA_SCALE, 100));
@@ -89,6 +98,38 @@
             updatePowerSave();
         } else if (action.equals(PowerManager.ACTION_POWER_SAVE_MODE_CHANGING)) {
             setPowerSave(intent.getBooleanExtra(PowerManager.EXTRA_POWER_SAVE_MODE, false));
+        } else if (action.equals(ACTION_LEVEL_TEST)) {
+            mTestmode = true;
+            mHandler.post(new Runnable() {
+                int curLevel = 0;
+                int incr = 1;
+                int saveLevel = mLevel;
+                boolean savePlugged = mPluggedIn;
+                Intent dummy = new Intent(Intent.ACTION_BATTERY_CHANGED);
+                @Override
+                public void run() {
+                    if (curLevel < 0) {
+                        mTestmode = false;
+                        dummy.putExtra("level", saveLevel);
+                        dummy.putExtra("plugged", savePlugged);
+                        dummy.putExtra("testmode", false);
+                    } else {
+                        dummy.putExtra("level", curLevel);
+                        dummy.putExtra("plugged", incr > 0 ? BatteryManager.BATTERY_PLUGGED_AC
+                                : 0);
+                        dummy.putExtra("testmode", true);
+                    }
+                    context.sendBroadcast(dummy);
+
+                    if (!mTestmode) return;
+
+                    curLevel += incr;
+                    if (curLevel == 100) {
+                        incr *= -1;
+                    }
+                    mHandler.postDelayed(this, 200);
+                }
+            });
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
index d907b00..cec0c0a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardMonitor.java
@@ -18,7 +18,8 @@
 
 import android.app.ActivityManager;
 import android.content.Context;
-
+import android.os.RemoteException;
+import android.view.WindowManagerGlobal;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.systemui.settings.CurrentUserTracker;
@@ -83,6 +84,20 @@
         return mCanSkipBouncer;
     }
 
+    public void unlock() {
+        try {
+            WindowManagerGlobal.getWindowManagerService().dismissKeyguard();
+        } catch (RemoteException e) {
+        }
+    }
+
+    public void lock() {
+        try {
+            WindowManagerGlobal.getWindowManagerService().lockNow(null /* options */);
+        } catch (RemoteException e) {
+        }
+    }
+
     public void notifyKeyguardState(boolean showing, boolean secure) {
         if (mShowing == showing && mSecure == secure) return;
         mShowing = showing;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index 0f9dd5c..e0823b4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -182,10 +182,10 @@
     @Override
     public void onUserSwitched(int newUserId) {
         mCurrentUserId = newUserId;
-        if (mUserManager.getUserInfo(newUserId).isRestricted()) {
+        final UserInfo newUserInfo = mUserManager.getUserInfo(newUserId);
+        if (newUserInfo.isRestricted()) {
             // VPN for a restricted profile is routed through its owner user
-            // TODO: http://b/22950929
-            mVpnUserId = UserHandle.USER_SYSTEM;
+            mVpnUserId = newUserInfo.restrictedProfileParentId;
         } else {
             mVpnUserId = mCurrentUserId;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
index a8d4f13..6931d1e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserInfoController.java
@@ -71,6 +71,11 @@
 
     public void addListener(OnUserInfoChangedListener callback) {
         mCallbacks.add(callback);
+        callback.onUserInfoChanged(mUserName, mUserDrawable);
+    }
+
+    public void remListener(OnUserInfoChangedListener callback) {
+        mCallbacks.remove(callback);
     }
 
     private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
index 8165894..e00b890 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/UserSwitcherController.java
@@ -752,9 +752,4 @@
             }
         }
     }
-
-    public static boolean isUserSwitcherAvailable(UserManager um) {
-        return UserManager.supportsMultipleUsers() && um.isUserSwitcherEnabled();
-    }
-
 }
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 2587b9f..bbe5dd9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/tv/TvStatusBar.java
@@ -171,7 +171,7 @@
     }
 
     @Override
-    public void onCameraLaunchGestureDetected() {
+    public void onCameraLaunchGestureDetected(int source) {
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
index 4387b33..04a51f0 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QSPagingSwitch.java
@@ -9,8 +9,8 @@
 public class QSPagingSwitch extends TunerSwitch {
 
     public static final String QS_PAGE_TILES =
-            "dwifi,dbt,inversion,dnd,cell,airplane,rotation,flashlight,location,"
-             + "hotspot,qwifi,qbt,qrotation,qflashlight,qairplane,cast";
+            "dwifi,dbt,dnd,cell,battery,user,rotation,flashlight,location,"
+             + "hotspot,qwifi,qbt,qlock,qflashlight,qairplane,inversion,cast";
 
     public QSPagingSwitch(Context context, AttributeSet attrs) {
         super(context, attrs);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index 772f866..703ee661 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -206,8 +206,8 @@
     private static class CustomHost extends QSTileHost {
 
         public CustomHost(Context context) {
-            super(context, null, null, null, null, null, null, null, null, null,
-                    null, null, new BlankSecurityController());
+            super(context, null, null, null, null, null, null, null, null, null, null,
+                    null, null, new BlankSecurityController(), null);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 920f875..9a78b6c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -39,7 +39,7 @@
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.tuner.TunerService.Tunable;
 
-import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
+import static com.android.systemui.BatteryMeterDrawable.SHOW_PERCENT_SETTING;
 
 public class TunerFragment extends PreferenceFragment {
 
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 50234b2..71559389 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -33,7 +33,7 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 
-import com.android.systemui.BatteryMeterView;
+import com.android.systemui.BatteryMeterDrawable;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
@@ -135,7 +135,7 @@
     public void clearAll() {
         // A couple special cases.
         Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
-        Settings.System.putString(mContentResolver, BatteryMeterView.SHOW_PERCENT_SETTING, null);
+        Settings.System.putString(mContentResolver, BatteryMeterDrawable.SHOW_PERCENT_SETTING, null);
         Intent intent = new Intent(DemoMode.ACTION_DEMO);
         intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
         mContext.sendBroadcast(intent);
diff --git a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
index 2727338..990d770 100644
--- a/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
+++ b/packages/services/PacProcessor/jni/com_android_pacprocessor_PacNative.cpp
@@ -130,7 +130,7 @@
     return jret;
 }
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "createV8ParserNativeLocked", "()Z",
         (void*)com_android_pacprocessor_PacNative_createV8ParserNativeLocked},
     { "destroyV8ParserNativeLocked", "()Z",
diff --git a/rs/jni/android_renderscript_RenderScript.cpp b/rs/jni/android_renderscript_RenderScript.cpp
index 0419d33..3759c91 100644
--- a/rs/jni/android_renderscript_RenderScript.cpp
+++ b/rs/jni/android_renderscript_RenderScript.cpp
@@ -611,7 +611,7 @@
     in_allocs[2] = (RsAllocation)C;
 
     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                         in_allocs, sizeof(in_allocs), nullptr,
+                         in_allocs, NELEM(in_allocs), nullptr,
                          &call, sizeof(call), nullptr, 0);
 }
 
@@ -646,7 +646,7 @@
     in_allocs[2] = (RsAllocation)C;
 
     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                         in_allocs, sizeof(in_allocs), nullptr,
+                         in_allocs, NELEM(in_allocs), nullptr,
                          &call, sizeof(call), nullptr, 0);
 }
 
@@ -681,7 +681,7 @@
     in_allocs[2] = (RsAllocation)C;
 
     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                         in_allocs, sizeof(in_allocs), nullptr,
+                         in_allocs, NELEM(in_allocs), nullptr,
                          &call, sizeof(call), nullptr, 0);
 }
 
@@ -707,7 +707,7 @@
     in_allocs[2] = (RsAllocation)C;
 
     rsScriptForEachMulti((RsContext)con, (RsScript)id, 0,
-                         in_allocs, sizeof(in_allocs), nullptr,
+                         in_allocs, NELEM(in_allocs), nullptr,
                          &call, sizeof(call), nullptr, 0);
 }
 
@@ -2494,7 +2494,7 @@
 
 static const char *classPathName = "android/renderscript/RenderScript";
 
-static JNINativeMethod methods[] = {
+static const JNINativeMethod methods[] = {
 {"_nInit",                         "()V",                                     (void*)_nInit },
 
 {"nDeviceCreate",                  "()J",                                     (void*)nDeviceCreate },
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 87a0b80..b52687a 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -45,28 +45,28 @@
     /**
      * Flag for enabling the screen magnification feature.
      *
-     * @see #setEnabledFeatures(int)
+     * @see #setUserAndEnabledFeatures(int, int)
      */
     static final int FLAG_FEATURE_SCREEN_MAGNIFIER = 0x00000001;
 
     /**
      * Flag for enabling the touch exploration feature.
      *
-     * @see #setEnabledFeatures(int)
+     * @see #setUserAndEnabledFeatures(int, int)
      */
     static final int FLAG_FEATURE_TOUCH_EXPLORATION = 0x00000002;
 
     /**
      * Flag for enabling the filtering key events feature.
      *
-     * @see #setEnabledFeatures(int)
+     * @see #setUserAndEnabledFeatures(int, int)
      */
     static final int FLAG_FEATURE_FILTER_KEY_EVENTS = 0x00000004;
 
     /**
      * Flag for enabling "Automatically click on mouse stop" feature.
      *
-     * @see #setEnabledFeatures(int)
+     * @see #setUserAndEnabledFeatures(int, int)
      */
     static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
 
@@ -97,6 +97,8 @@
 
     private boolean mInstalled;
 
+    private int mUserId;
+
     private int mEnabledFeatures;
 
     private TouchExplorer mTouchExplorer;
@@ -327,13 +329,14 @@
         /* do nothing */
     }
 
-    void setEnabledFeatures(int enabledFeatures) {
-        if (mEnabledFeatures == enabledFeatures) {
+    void setUserAndEnabledFeatures(int userId, int enabledFeatures) {
+        if (mEnabledFeatures == enabledFeatures && mUserId == userId) {
             return;
         }
         if (mInstalled) {
             disableFeatures();
         }
+        mUserId = userId;
         mEnabledFeatures = enabledFeatures;
         if (mInstalled) {
             enableFeatures();
@@ -350,7 +353,7 @@
         resetStreamState();
 
         if ((mEnabledFeatures & FLAG_FEATURE_AUTOCLICK) != 0) {
-            mAutoclickController = new AutoclickController(mContext);
+            mAutoclickController = new AutoclickController(mContext, mUserId);
             addFirstEventHandler(mAutoclickController);
         }
 
@@ -360,7 +363,7 @@
         }
 
         if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
-            mScreenMagnifier = new ScreenMagnifier(mContext,
+            mScreenMagnifier = new ScreenMagnifier(mContext, mUserId,
                     Display.DEFAULT_DISPLAY, mAms);
             addFirstEventHandler(mScreenMagnifier);
         }
@@ -386,7 +389,7 @@
         mEventHandler = handler;
     }
 
-    void disableFeatures() {
+    private void disableFeatures() {
         if (mAutoclickController != null) {
             mAutoclickController.onDestroy();
             mAutoclickController = null;
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 91c3d48..749a080 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -967,8 +967,8 @@
 
         List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
                 new Intent(AccessibilityService.SERVICE_INTERFACE),
-                PackageManager.GET_SERVICES 
-                  | PackageManager.GET_META_DATA 
+                PackageManager.GET_SERVICES
+                  | PackageManager.GET_META_DATA
                   | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                 mCurrentUserId);
 
@@ -1296,11 +1296,11 @@
                     inputFilter = mInputFilter;
                     setInputFilter = true;
                 }
-                mInputFilter.setEnabledFeatures(flags);
+                mInputFilter.setUserAndEnabledFeatures(userState.mUserId, flags);
             } else {
                 if (mHasInputFilter) {
                     mHasInputFilter = false;
-                    mInputFilter.disableFeatures();
+                    mInputFilter.setUserAndEnabledFeatures(userState.mUserId, 0);
                     inputFilter = null;
                     setInputFilter = true;
                 }
@@ -3217,7 +3217,8 @@
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ALERT:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG:
                 case WindowManager.LayoutParams.TYPE_SYSTEM_ERROR:
-                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY: {
+                case WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY:
+                case WindowManager.LayoutParams.TYPE_DOCK_DIVIDER: {
                     return AccessibilityWindowInfo.TYPE_SYSTEM;
                 }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
index 8989625..3283378 100644
--- a/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
+++ b/services/accessibility/java/com/android/server/accessibility/AutoclickController.java
@@ -51,6 +51,8 @@
  *
  * It is expected that each instance will receive mouse events from a single mouse device. User of
  * the class should handle cases where multiple mouse devices are present.
+ *
+ * Each instance is associated to a single user (and it does not handle user switch itself).
  */
 public class AutoclickController implements EventStreamTransformation {
 
@@ -60,13 +62,15 @@
 
     private EventStreamTransformation mNext;
     private final Context mContext;
+    private final int mUserId;
 
     // Lazily created on the first mouse motion event.
     private ClickScheduler mClickScheduler;
     private ClickDelayObserver mClickDelayObserver;
 
-    public AutoclickController(Context context) {
+    public AutoclickController(Context context, int userId) {
         mContext = context;
+        mUserId = userId;
     }
 
     @Override
@@ -75,7 +79,7 @@
             if (mClickScheduler == null) {
                 Handler handler = new Handler(mContext.getMainLooper());
                 mClickScheduler = new ClickScheduler(handler, DEFAULT_CLICK_DELAY_MS);
-                mClickDelayObserver = new ClickDelayObserver(handler);
+                mClickDelayObserver = new ClickDelayObserver(mUserId, handler);
                 mClickDelayObserver.start(mContext.getContentResolver(), mClickScheduler);
             }
 
@@ -168,9 +172,11 @@
 
         private ContentResolver mContentResolver;
         private ClickScheduler mClickScheduler;
+        private final int mUserId;
 
-        public ClickDelayObserver(Handler handler) {
+        public ClickDelayObserver(int userId, Handler handler) {
             super(handler);
+            mUserId = userId;
         }
 
         /**
@@ -199,7 +205,7 @@
             mContentResolver = contentResolver;
             mClickScheduler = clickScheduler;
             mContentResolver.registerContentObserver(mAutoclickDelaySettingUri, false, this,
-                    UserHandle.USER_ALL);
+                    mUserId);
 
             // Initialize mClickScheduler's initial delay value.
             onChange(true, mAutoclickDelaySettingUri);
@@ -222,10 +228,9 @@
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (mAutoclickDelaySettingUri.equals(uri)) {
-                // TODO: Plumb current user id down to here and use getIntForUser.
-                int delay = Settings.Secure.getInt(
+                int delay = Settings.Secure.getIntForUser(
                         mContentResolver, Settings.Secure.ACCESSIBILITY_AUTOCLICK_DELAY,
-                        DEFAULT_CLICK_DELAY_MS);
+                        DEFAULT_CLICK_DELAY_MS, mUserId);
                 mClickScheduler.updateDelay(delay);
             }
         }
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index 37276bd..8845bc0 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -29,7 +29,6 @@
 import android.os.Binder;
 import android.os.Handler;
 import android.os.Message;
-import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.TextUtils;
 import android.util.Property;
@@ -137,6 +136,8 @@
 
     private final AccessibilityManagerService mAms;
 
+    private final int mUserId;
+
     private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout();
     private final int mMultiTapTimeSlop;
     private final int mTapDistanceSlop;
@@ -188,8 +189,10 @@
         }
     };
 
-    public ScreenMagnifier(Context context, int displayId, AccessibilityManagerService service) {
+    public ScreenMagnifier(Context context, int userId, int displayId,
+            AccessibilityManagerService service) {
         mContext = context;
+        mUserId = userId;
         mWindowManager = LocalServices.getService(WindowManagerInternal.class);
         mAms = service;
 
@@ -813,33 +816,12 @@
             while (mDelayedEventQueue != null) {
                 MotionEventInfo info = mDelayedEventQueue;
                 mDelayedEventQueue = info.mNext;
-                final long offset = SystemClock.uptimeMillis() - info.mCachedTimeMillis;
-                MotionEvent event = obtainEventWithOffsetTimeAndDownTime(info.mEvent, offset);
-                MotionEvent rawEvent = obtainEventWithOffsetTimeAndDownTime(info.mRawEvent, offset);
-                ScreenMagnifier.this.onMotionEvent(event, rawEvent, info.mPolicyFlags);
-                event.recycle();
-                rawEvent.recycle();
+                ScreenMagnifier.this.onMotionEvent(info.mEvent, info.mRawEvent,
+                        info.mPolicyFlags);
                 info.recycle();
             }
         }
 
-        private MotionEvent obtainEventWithOffsetTimeAndDownTime(MotionEvent event, long offset) {
-            final int pointerCount = event.getPointerCount();
-            PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
-            PointerProperties[] properties = getTempPointerPropertiesWithMinSize(pointerCount);
-            for (int i = 0; i < pointerCount; i++) {
-                event.getPointerCoords(i, coords[i]);
-                event.getPointerProperties(i, properties[i]);
-            }
-            final long downTime = event.getDownTime() + offset;
-            final long eventTime = event.getEventTime() + offset;
-            return MotionEvent.obtain(downTime, eventTime,
-                    event.getAction(), pointerCount, properties, coords,
-                    event.getMetaState(), event.getButtonState(),
-                    1.0f, 1.0f, event.getDeviceId(), event.getEdgeFlags(),
-                    event.getSource(), event.getFlags());
-        }
-
         private void clearDelayedMotionEvents() {
             while (mDelayedEventQueue != null) {
                 MotionEventInfo info = mDelayedEventQueue;
@@ -882,17 +864,17 @@
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
-                Settings.Secure.putFloat(mContext.getContentResolver(),
-                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale);
+                Settings.Secure.putFloatForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE, scale, mUserId);
                 return null;
             }
         }.execute();
     }
 
     private float getPersistedScale() {
-        return Settings.Secure.getFloat(mContext.getContentResolver(),
+        return Settings.Secure.getFloatForUser(mContext.getContentResolver(),
                 Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_SCALE,
-                DEFAULT_MAGNIFICATION_SCALE);
+                DEFAULT_MAGNIFICATION_SCALE, mUserId);
     }
 
     private static boolean isScreenMagnificationAutoUpdateEnabled(Context context) {
@@ -915,7 +897,6 @@
         public MotionEvent mEvent;
         public MotionEvent mRawEvent;
         public int mPolicyFlags;
-        public long mCachedTimeMillis;
 
         public static MotionEventInfo obtain(MotionEvent event, MotionEvent rawEvent,
                 int policyFlags) {
@@ -940,7 +921,6 @@
             mEvent = MotionEvent.obtain(event);
             mRawEvent = MotionEvent.obtain(rawEvent);
             mPolicyFlags = policyFlags;
-            mCachedTimeMillis = SystemClock.uptimeMillis();
         }
 
         public void recycle() {
@@ -964,7 +944,6 @@
             mRawEvent.recycle();
             mRawEvent = null;
             mPolicyFlags = 0;
-            mCachedTimeMillis = 0;
         }
     }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
index 85730cd..c3f5c43 100644
--- a/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/TouchExplorer.java
@@ -29,6 +29,7 @@
 import android.os.Handler;
 import android.os.SystemClock;
 import android.util.Slog;
+import android.view.GestureDetector;
 import android.view.InputDevice;
 import android.view.KeyEvent;
 import android.view.MotionEvent;
@@ -114,9 +115,6 @@
     // Timeout within which we try to detect a tap.
     private final int mTapTimeout;
 
-    // Timeout within which we try to detect a double tap.
-    private final int mDoubleTapTimeout;
-
     // Slop between the down and up tap to be a tap.
     private final int mTouchSlop;
 
@@ -230,7 +228,6 @@
         mInjectedPointerTracker = new InjectedPointerTracker();
         mTapTimeout = ViewConfiguration.getTapTimeout();
         mDetermineUserIntentTimeout = ViewConfiguration.getDoubleTapTimeout();
-        mDoubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();
         mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
         mDoubleTapSlop = ViewConfiguration.get(context).getScaledDoubleTapSlop();
         mHandler = new Handler(context.getMainLooper());
@@ -248,7 +245,7 @@
         mSendTouchInteractionEndDelayed = new SendAccessibilityEventDelayed(
                 AccessibilityEvent.TYPE_TOUCH_INTERACTION_END,
                 mDetermineUserIntentTimeout);
-        mDoubleTapDetector = new DoubleTapDetector();
+        mDoubleTapDetector = new DoubleTapDetector(mContext);
         final float density = context.getResources().getDisplayMetrics().density;
         mScaledMinPointerDistanceToUseMiddleLocation =
             (int) (MIN_POINTER_DISTANCE_TO_USE_MIDDLE_LOCATION_DIP * density);
@@ -1109,66 +1106,63 @@
         }
     }
 
-    private class DoubleTapDetector {
-        private MotionEvent mDownEvent;
-        private MotionEvent mFirstTapEvent;
+    private class DoubleTapDetector extends GestureDetector.SimpleOnGestureListener {
+        private final GestureDetector mGestureDetector;
+        private boolean mFirstTapDetected;
+        private boolean mDoubleTapDetected;
 
-        public void onMotionEvent(MotionEvent event, int policyFlags) {
-            final int actionIndex = event.getActionIndex();
-            final int action = event.getActionMasked();
-            switch (action) {
-                case MotionEvent.ACTION_DOWN:
-                case MotionEvent.ACTION_POINTER_DOWN: {
-                    if (mFirstTapEvent != null
-                            && !GestureUtils.isSamePointerContext(mFirstTapEvent, event)) {
-                        clear();
-                    }
-                    mDownEvent = MotionEvent.obtain(event);
-                } break;
-                case MotionEvent.ACTION_UP:
-                case MotionEvent.ACTION_POINTER_UP: {
-                    if (mDownEvent == null) {
-                        return;
-                    }
-                    if (!GestureUtils.isSamePointerContext(mDownEvent, event)) {
-                        clear();
-                        return;
-                    }
-                    if (GestureUtils.isTap(mDownEvent, event, mTapTimeout, mTouchSlop,
-                            actionIndex)) {
-                        if (mFirstTapEvent == null || GestureUtils.isTimedOut(mFirstTapEvent,
-                                event, mDoubleTapTimeout)) {
-                            mFirstTapEvent = MotionEvent.obtain(event);
-                            mDownEvent.recycle();
-                            mDownEvent = null;
-                            return;
-                        }
-                        if (GestureUtils.isMultiTap(mFirstTapEvent, event, mDoubleTapTimeout,
-                                mDoubleTapSlop, actionIndex)) {
-                            onDoubleTap(event, policyFlags);
-                            mFirstTapEvent.recycle();
-                            mFirstTapEvent = null;
-                            mDownEvent.recycle();
-                            mDownEvent = null;
-                            return;
-                        }
-                        mFirstTapEvent.recycle();
-                        mFirstTapEvent = null;
-                    } else {
-                        if (mFirstTapEvent != null) {
-                            mFirstTapEvent.recycle();
-                            mFirstTapEvent = null;
-                        }
-                    }
-                    mDownEvent.recycle();
-                    mDownEvent = null;
-                } break;
-            }
+        DoubleTapDetector(Context context) {
+            mGestureDetector = new GestureDetector(context, this);
+            mGestureDetector.setOnDoubleTapListener(this);
         }
 
-        public void onDoubleTap(MotionEvent secondTapUp, int policyFlags) {
+        public void onMotionEvent(MotionEvent event, int policyFlags) {
+            switch (event.getActionMasked()) {
+                case MotionEvent.ACTION_DOWN:
+                    mDoubleTapDetected = false;
+                    break;
+
+                case MotionEvent.ACTION_UP:
+                    maybeFinishDoubleTap(event, policyFlags);
+                    break;
+            }
+            mGestureDetector.onTouchEvent(event);
+        }
+
+        @Override
+        public boolean onDown(MotionEvent event) {
+            return true;
+        }
+
+        @Override
+        public boolean onSingleTapUp(MotionEvent event) {
+            mFirstTapDetected = true;
+            return false;
+        }
+
+        @Override
+        public boolean onSingleTapConfirmed(MotionEvent event) {
+            clear();
+            return false;
+        }
+
+        @Override
+        public boolean onDoubleTap(MotionEvent event) {
+            // The processing of the double tap is deferred until the finger is
+            // lifted, so that we can detect a long press on the second tap.
+            mDoubleTapDetected = true;
+            return true;
+        }
+
+        private void maybeFinishDoubleTap(MotionEvent event, int policyFlags) {
+            if (!mDoubleTapDetected) {
+                return;
+            }
+
+            clear();
+
             // This should never be called when more than two pointers are down.
-            if (secondTapUp.getPointerCount() > 2) {
+            if (event.getPointerCount() > 2) {
                 return;
             }
 
@@ -1184,8 +1178,8 @@
                 mSendTouchInteractionEndDelayed.forceSendAndRemove();
             }
 
-            final int pointerId = secondTapUp.getPointerId(secondTapUp.getActionIndex());
-            final int pointerIndex = secondTapUp.findPointerIndex(pointerId);
+            final int pointerId = event.getPointerId(event.getActionIndex());
+            final int pointerIndex = event.findPointerIndex(pointerId);
 
             Point clickLocation = mTempPoint;
             final int result = computeClickLocation(clickLocation);
@@ -1196,34 +1190,28 @@
             // Do the click.
             PointerProperties[] properties = new PointerProperties[1];
             properties[0] = new PointerProperties();
-            secondTapUp.getPointerProperties(pointerIndex, properties[0]);
+            event.getPointerProperties(pointerIndex, properties[0]);
             PointerCoords[] coords = new PointerCoords[1];
             coords[0] = new PointerCoords();
             coords[0].x = clickLocation.x;
             coords[0].y = clickLocation.y;
-            MotionEvent event = MotionEvent.obtain(secondTapUp.getDownTime(),
-                    secondTapUp.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
-                    coords, 0, 0, 1.0f, 1.0f, secondTapUp.getDeviceId(), 0,
-                    secondTapUp.getSource(), secondTapUp.getFlags());
+            MotionEvent click_event = MotionEvent.obtain(event.getDownTime(),
+                    event.getEventTime(), MotionEvent.ACTION_DOWN, 1, properties,
+                    coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0,
+                    event.getSource(), event.getFlags());
             final boolean targetAccessibilityFocus = (result == CLICK_LOCATION_ACCESSIBILITY_FOCUS);
-            sendActionDownAndUp(event, policyFlags, targetAccessibilityFocus);
-            event.recycle();
+            sendActionDownAndUp(click_event, policyFlags, targetAccessibilityFocus);
+            click_event.recycle();
+            return;
         }
 
         public void clear() {
-            if (mDownEvent != null) {
-                mDownEvent.recycle();
-                mDownEvent = null;
-            }
-            if (mFirstTapEvent != null) {
-                mFirstTapEvent.recycle();
-                mFirstTapEvent = null;
-            }
+            mFirstTapDetected = false;
+            mDoubleTapDetected = false;
         }
 
         public boolean firstTapDetected() {
-            return mFirstTapEvent != null
-                && SystemClock.uptimeMillis() - mFirstTapEvent.getEventTime() < mDoubleTapTimeout;
+            return mFirstTapDetected;
         }
     }
 
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 6190a5a..a7e6f11 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -754,6 +754,8 @@
         IntentFilter intentFilter = new IntentFilter();
         intentFilter.addAction(Intent.ACTION_USER_STARTING);
         intentFilter.addAction(Intent.ACTION_USER_STOPPING);
+        intentFilter.addAction(Intent.ACTION_USER_ADDED);
+        intentFilter.addAction(Intent.ACTION_USER_REMOVED);
         mContext.registerReceiverAsUser(
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
 
@@ -3525,6 +3527,26 @@
         }
     }
 
+    private void onUserAdded(int userId) {
+        synchronized(mVpns) {
+            final int vpnsSize = mVpns.size();
+            for (int i = 0; i < vpnsSize; i++) {
+                Vpn vpn = mVpns.valueAt(i);
+                vpn.onUserAdded(userId);
+            }
+        }
+    }
+
+    private void onUserRemoved(int userId) {
+        synchronized(mVpns) {
+            final int vpnsSize = mVpns.size();
+            for (int i = 0; i < vpnsSize; i++) {
+                Vpn vpn = mVpns.valueAt(i);
+                vpn.onUserRemoved(userId);
+            }
+        }
+    }
+
     private BroadcastReceiver mUserIntentReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -3536,6 +3558,10 @@
                 onUserStart(userId);
             } else if (Intent.ACTION_USER_STOPPING.equals(action)) {
                 onUserStop(userId);
+            } else if (Intent.ACTION_USER_ADDED.equals(action)) {
+                onUserAdded(userId);
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
+                onUserRemoved(userId);
             }
         }
     };
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 0c6eb40..ebcdf7c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -31,6 +31,8 @@
 import android.database.ContentObserver;
 import android.hardware.Sensor;
 import android.hardware.SensorManager;
+import android.hardware.SensorEvent;
+import android.hardware.SensorEventListener;
 import android.hardware.TriggerEvent;
 import android.hardware.TriggerEventListener;
 import android.hardware.display.DisplayManager;
@@ -111,7 +113,7 @@
     private INetworkPolicyManager mNetworkPolicyManager;
     private DisplayManager mDisplayManager;
     private SensorManager mSensorManager;
-    private Sensor mSigMotionSensor;
+    private Sensor mMotionSensor;
     private LocationManager mLocationManager;
     private LocationRequest mLocationRequest;
     private PendingIntent mSensingAlarmIntent;
@@ -123,7 +125,6 @@
     private boolean mForceIdle;
     private boolean mScreenOn;
     private boolean mCharging;
-    private boolean mSigMotionActive;
     private boolean mSensing;
     private boolean mNotMoving;
     private boolean mLocating;
@@ -268,13 +269,57 @@
         }
     };
 
-    private final TriggerEventListener mSigMotionListener = new TriggerEventListener() {
-        @Override public void onTrigger(TriggerEvent event) {
+    private final class MotionListener extends TriggerEventListener
+            implements SensorEventListener {
+
+        boolean active = false;
+
+        @Override
+        public void onTrigger(TriggerEvent event) {
             synchronized (DeviceIdleController.this) {
-                significantMotionLocked();
+                active = false;
+                motionLocked();
             }
         }
-    };
+
+        @Override
+        public void onSensorChanged(SensorEvent event) {
+            synchronized (DeviceIdleController.this) {
+                mSensorManager.unregisterListener(this, mMotionSensor);
+                active = false;
+                motionLocked();
+            }
+        }
+
+        @Override
+        public void onAccuracyChanged(Sensor sensor, int accuracy) {}
+
+        public boolean registerLocked() {
+            boolean success = false;
+            if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+                success = mSensorManager.requestTriggerSensor(mMotionListener, mMotionSensor);
+            } else {
+                success = mSensorManager.registerListener(
+                        mMotionListener, mMotionSensor, SensorManager.SENSOR_DELAY_NORMAL);
+            }
+            if (success) {
+                active = true;
+            } else {
+                Slog.e(TAG, "Unable to register for " + mMotionSensor);
+            }
+            return success;
+        }
+
+        public void unregisterLocked() {
+            if (mMotionSensor.getReportingMode() == Sensor.REPORTING_MODE_ONE_SHOT) {
+                mSensorManager.cancelTriggerSensor(mMotionListener, mMotionSensor);
+            } else {
+                mSensorManager.unregisterListener(mMotionListener);
+            }
+            active = false;
+        }
+    }
+    private final MotionListener mMotionListener = new MotionListener();
 
     private final LocationListener mGenericLocationListener = new LocationListener() {
         @Override
@@ -349,7 +394,7 @@
          * This is the time, after becoming inactive, at which we start looking at the
          * motion sensor to determine if the device is being left alone.  We don't do this
          * immediately after going inactive just because we don't want to be continually running
-         * the significant motion sensor whenever the screen is off.
+         * the motion sensor whenever the screen is off.
          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
          * @see #KEY_INACTIVE_TIMEOUT
          */
@@ -392,7 +437,7 @@
 
         /**
          * This is the time, after the inactive timeout elapses, that we will wait looking
-         * for significant motion until we truly consider the device to be idle.
+         * for motion until we truly consider the device to be idle.
          * @see Settings.Global#DEVICE_IDLE_CONSTANTS
          * @see #KEY_IDLE_AFTER_INACTIVE_TIMEOUT
          */
@@ -886,18 +931,19 @@
                 int sigMotionSensorId = getContext().getResources().getInteger(
                         com.android.internal.R.integer.config_autoPowerModeAnyMotionSensor);
                 if (sigMotionSensorId > 0) {
-                    mSigMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
+                    mMotionSensor = mSensorManager.getDefaultSensor(sigMotionSensorId, true);
                 }
-                if (mSigMotionSensor == null && getContext().getResources().getBoolean(
+                if (mMotionSensor == null && getContext().getResources().getBoolean(
                         com.android.internal.R.bool.config_autoPowerModePreferWristTilt)) {
-                    mSigMotionSensor = mSensorManager.getDefaultSensor(
-                            Sensor.TYPE_WRIST_TILT_GESTURE);
+                    mMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_WRIST_TILT_GESTURE, true);
                 }
-                if (mSigMotionSensor == null) {
+                if (mMotionSensor == null) {
                     // As a last ditch, fall back to SMD.
-                    mSigMotionSensor = mSensorManager.getDefaultSensor(
-                            Sensor.TYPE_SIGNIFICANT_MOTION);
+                    mMotionSensor = mSensorManager.getDefaultSensor(
+                            Sensor.TYPE_SIGNIFICANT_MOTION, true);
                 }
+
                 if (getContext().getResources().getBoolean(
                         com.android.internal.R.bool.config_autoPowerModePrefetchLocation)) {
                     mLocationManager = (LocationManager) getContext().getSystemService(
@@ -1242,7 +1288,7 @@
         cancelAlarmLocked();
         cancelSensingAlarmLocked();
         cancelLocatingLocked();
-        stopMonitoringSignificantMotion();
+        stopMonitoringMotionLocked();
         mAnyMotionDetector.stop();
     }
 
@@ -1271,8 +1317,8 @@
         switch (mState) {
             case STATE_INACTIVE:
                 // We have now been inactive long enough, it is time to start looking
-                // for significant motion and sleep some more while doing so.
-                startMonitoringSignificantMotion();
+                // for motion and sleep some more while doing so.
+                startMonitoringMotionLocked();
                 scheduleAlarmLocked(mConstants.IDLE_AFTER_INACTIVE_TIMEOUT, false);
                 // Reset the upcoming idle delays.
                 mNextIdlePendingDelay = mConstants.IDLE_PENDING_TIMEOUT;
@@ -1353,17 +1399,16 @@
         }
     }
 
-    void significantMotionLocked() {
-        if (DEBUG) Slog.d(TAG, "significantMotionLocked()");
-        // When the sensor goes off, its trigger is automatically removed.
-        mSigMotionActive = false;
+    void motionLocked() {
+        if (DEBUG) Slog.d(TAG, "motionLocked()");
+        // The motion sensor will have been disabled at this point
         handleMotionDetectedLocked(mConstants.MOTION_INACTIVE_TIMEOUT, "motion");
     }
 
     void handleMotionDetectedLocked(long timeout, String type) {
         // The device is not yet active, so we want to go back to the pending idle
-        // state to wait again for no motion.  Note that we only monitor for significant
-        // motion after moving out of the inactive state, so no need to worry about that.
+        // state to wait again for no motion.  Note that we only monitor for motion
+        // after moving out of the inactive state, so no need to worry about that.
         if (mState != STATE_ACTIVE) {
             scheduleReportActiveLocked(type, Process.myUid());
             mState = STATE_ACTIVE;
@@ -1405,19 +1450,17 @@
         }
     }
 
-    void startMonitoringSignificantMotion() {
-        if (DEBUG) Slog.d(TAG, "startMonitoringSignificantMotion()");
-        if (mSigMotionSensor != null && !mSigMotionActive) {
-            mSensorManager.requestTriggerSensor(mSigMotionListener, mSigMotionSensor);
-            mSigMotionActive = true;
+    void startMonitoringMotionLocked() {
+        if (DEBUG) Slog.d(TAG, "startMonitoringMotionLocked()");
+        if (mMotionSensor != null && !mMotionListener.active) {
+            mMotionListener.registerLocked();
         }
     }
 
-    void stopMonitoringSignificantMotion() {
-        if (DEBUG) Slog.d(TAG, "stopMonitoringSignificantMotion()");
-        if (mSigMotionActive) {
-            mSensorManager.cancelTriggerSensor(mSigMotionListener, mSigMotionSensor);
-            mSigMotionActive = false;
+    void stopMonitoringMotionLocked() {
+        if (DEBUG) Slog.d(TAG, "stopMonitoringMotionLocked()");
+        if (mMotionSensor != null && mMotionListener.active) {
+            mMotionListener.unregisterLocked();
         }
     }
 
@@ -1446,7 +1489,7 @@
 
     void scheduleAlarmLocked(long delay, boolean idleUntil) {
         if (DEBUG) Slog.d(TAG, "scheduleAlarmLocked(" + delay + ", " + idleUntil + ")");
-        if (mSigMotionSensor == null) {
+        if (mMotionSensor == null) {
             // If there is no motion sensor on this device, then we won't schedule
             // alarms, because we can't determine if the device is not moving.  This effectively
             // turns off normal execution of device idling, although it is still possible to
@@ -1929,11 +1972,11 @@
 
             pw.print("  mEnabled="); pw.println(mEnabled);
             pw.print("  mForceIdle="); pw.println(mForceIdle);
-            pw.print("  mSigMotionSensor="); pw.println(mSigMotionSensor);
+            pw.print("  mMotionSensor="); pw.println(mMotionSensor);
             pw.print("  mCurDisplay="); pw.println(mCurDisplay);
             pw.print("  mScreenOn="); pw.println(mScreenOn);
             pw.print("  mCharging="); pw.println(mCharging);
-            pw.print("  mSigMotionActive="); pw.println(mSigMotionActive);
+            pw.print("  mMotionActive="); pw.println(mMotionListener.active);
             pw.print("  mSensing="); pw.print(mSensing); pw.print(" mNotMoving=");
                     pw.println(mNotMoving);
             pw.print("  mLocating="); pw.print(mLocating); pw.print(" mHasGps=");
diff --git a/services/core/java/com/android/server/GestureLauncherService.java b/services/core/java/com/android/server/GestureLauncherService.java
index 7c85001..f245985 100644
--- a/services/core/java/com/android/server/GestureLauncherService.java
+++ b/services/core/java/com/android/server/GestureLauncherService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.ActivityManager;
+import android.app.StatusBarManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -263,7 +264,8 @@
         }
         if (launched) {
             Slog.i(TAG, "Power button double tap gesture detected, launching camera.");
-            launched = handleCameraLaunchGesture(false /* useWakelock */);
+            launched = handleCameraLaunchGesture(false /* useWakelock */,
+                    StatusBarManager.CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP);
             if (launched) {
                 MetricsLogger.action(mContext, MetricsLogger.ACTION_DOUBLE_TAP_POWER_CAMERA_GESTURE,
                         (int) doubleTapInterval);
@@ -276,7 +278,7 @@
     /**
      * @return true if camera was launched, false otherwise.
      */
-    private boolean handleCameraLaunchGesture(boolean useWakelock) {
+    private boolean handleCameraLaunchGesture(boolean useWakelock, int source) {
         boolean userSetupComplete = Settings.Secure.getInt(mContext.getContentResolver(),
                 Settings.Secure.USER_SETUP_COMPLETE, 0) != 0;
         if (!userSetupComplete) {
@@ -295,7 +297,7 @@
         }
         StatusBarManagerInternal service = LocalServices.getService(
                 StatusBarManagerInternal.class);
-        service.onCameraLaunchGestureDetected();
+        service.onCameraLaunchGestureDetected(source);
         return true;
     }
 
@@ -334,7 +336,8 @@
                     Slog.d(TAG, String.format("Received a camera launch event: " +
                             "values=[%.4f, %.4f, %.4f].", values[0], values[1], values[2]));
                 }
-                if (handleCameraLaunchGesture(true /* useWakelock */)) {
+                if (handleCameraLaunchGesture(true /* useWakelock */,
+                        StatusBarManager.CAMERA_LAUNCH_SOURCE_WIGGLE)) {
                     MetricsLogger.action(mContext, MetricsLogger.ACTION_WIGGLE_CAMERA_GESTURE);
                     trackCameraLaunchEvent(event);
                 }
diff --git a/services/core/java/com/android/server/LocationManagerService.java b/services/core/java/com/android/server/LocationManagerService.java
index 885c765..087ddd6 100644
--- a/services/core/java/com/android/server/LocationManagerService.java
+++ b/services/core/java/com/android/server/LocationManagerService.java
@@ -211,8 +211,8 @@
             new ArrayList<LocationProviderProxy>();
 
     // current active user on the device - other users are denied location data
-    private int mCurrentUserId = UserHandle.USER_OWNER;
-    private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_OWNER };
+    private int mCurrentUserId = UserHandle.USER_SYSTEM;
+    private int[] mCurrentUserProfiles = new int[] { UserHandle.USER_SYSTEM };
 
     public LocationManagerService(Context context) {
         super();
@@ -1832,7 +1832,8 @@
 
         // geo-fence manager uses the public location API, need to clear identity
         int uid = Binder.getCallingUid();
-        if (UserHandle.getUserId(uid) != UserHandle.USER_OWNER) {
+        // TODO: http://b/23822629
+        if (UserHandle.getUserId(uid) != UserHandle.USER_SYSTEM) {
             // temporary measure until geofences work for secondary users
             Log.w(TAG, "proximity alerts are currently available only to the primary user");
             return;
diff --git a/services/core/java/com/android/server/ThermalObserver.java b/services/core/java/com/android/server/ThermalObserver.java
new file mode 100644
index 0000000..aee28fb
--- /dev/null
+++ b/services/core/java/com/android/server/ThermalObserver.java
@@ -0,0 +1,146 @@
+/*
+ * Copyright (C) 2015 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;
+
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Message;
+import android.os.PowerManager;
+import android.os.UEventObserver;
+import android.os.UserHandle;
+
+import java.io.FileDescriptor;
+import java.io.PrintWriter;
+
+/**
+ * ThermalObserver for monitoring temperature changes.
+ */
+public class ThermalObserver extends SystemService {
+    private static final String TAG = "ThermalObserver";
+
+    private static final String CALLSTATE_UEVENT_MATCH =
+            "DEVPATH=/devices/virtual/switch/thermalstate";
+
+    private static final int MSG_THERMAL_STATE_CHANGED = 0;
+
+    private static final int SWITCH_STATE_NORMAL = 0;
+    private static final int SWITCH_STATE_WARNING = 1;
+    private static final int SWITCH_STATE_EXCEEDED = 2;
+
+    private final PowerManager mPowerManager;
+    private final PowerManager.WakeLock mWakeLock;
+
+    private final Object mLock = new Object();
+    private Integer mLastState;
+
+    private final UEventObserver mThermalWarningObserver = new UEventObserver() {
+        @Override
+        public void onUEvent(UEventObserver.UEvent event) {
+            updateLocked(Integer.parseInt(event.get("SWITCH_STATE")));
+        }
+    };
+
+    private final Handler mHandler = new Handler(true /*async*/) {
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_THERMAL_STATE_CHANGED:
+                    handleThermalStateChange(msg.arg1);
+                    mWakeLock.release();
+                    break;
+            }
+        }
+    };
+
+    public ThermalObserver(Context context) {
+        super(context);
+        mPowerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
+        mWakeLock = mPowerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
+
+        mThermalWarningObserver.startObserving(CALLSTATE_UEVENT_MATCH);
+    }
+
+    private void updateLocked(int state) {
+        Message message = new Message();
+        message.what = MSG_THERMAL_STATE_CHANGED;
+        message.arg1 = state;
+
+        mWakeLock.acquire();
+        mHandler.sendMessage(message);
+    }
+
+    private void handleThermalStateChange(int state) {
+        synchronized (mLock) {
+            mLastState = state;
+            Intent intent = new Intent(Intent.ACTION_THERMAL_EVENT);
+            intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING);
+
+            final int thermalState;
+
+            switch (state) {
+                case SWITCH_STATE_WARNING:
+                    thermalState = Intent.EXTRA_THERMAL_STATE_WARNING;
+                    break;
+                case SWITCH_STATE_EXCEEDED:
+                    thermalState = Intent.EXTRA_THERMAL_STATE_EXCEEDED;
+                    break;
+                case SWITCH_STATE_NORMAL:
+                default:
+                    thermalState = Intent.EXTRA_THERMAL_STATE_NORMAL;
+                    break;
+            }
+
+            intent.putExtra(Intent.EXTRA_THERMAL_STATE, thermalState);
+
+            getContext().sendBroadcastAsUser(intent, UserHandle.ALL);
+        }
+    }
+
+    @Override
+    public void onStart() {
+        publishBinderService(TAG, new BinderService());
+    }
+
+    private final class BinderService extends Binder {
+        @Override
+        protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
+            if (getContext().checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
+                    != PackageManager.PERMISSION_GRANTED) {
+                pw.println("Permission Denial: can't dump thermal observer service from from pid="
+                        + Binder.getCallingPid()
+                        + ", uid=" + Binder.getCallingUid());
+                return;
+            }
+
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    if (args == null || args.length == 0 || "-a".equals(args[0])) {
+                        pw.println("Current Thermal Observer Service state:");
+                        pw.println("  last state change: "
+                                + (mLastState != null ? mLastState : "none"));
+                    }
+                }
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index dbf1288..6b34612 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -29,6 +29,7 @@
 import android.accounts.IAccountAuthenticatorResponse;
 import android.accounts.IAccountManager;
 import android.accounts.IAccountManagerResponse;
+import android.annotation.NonNull;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -2526,6 +2527,7 @@
      * Returns the accounts visible to the client within the context of a specific user
      * @hide
      */
+    @NonNull
     public Account[] getAccounts(int userId, String opPackageName) {
         int callingUid = Binder.getCallingUid();
         List<String> visibleAccountTypes = getTypesVisibleToCaller(callingUid, userId,
@@ -2551,6 +2553,7 @@
      *
      * @hide
      */
+    @NonNull
     public AccountAndUser[] getRunningAccounts() {
         final int[] runningUserIds;
         try {
@@ -2563,6 +2566,7 @@
     }
 
     /** {@hide} */
+    @NonNull
     public AccountAndUser[] getAllAccounts() {
         final List<UserInfo> users = getUserManager().getUsers();
         final int[] userIds = new int[users.size()];
@@ -2572,6 +2576,7 @@
         return getAccounts(userIds);
     }
 
+    @NonNull
     private AccountAndUser[] getAccounts(int[] userIds) {
         final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
         for (int userId : userIds) {
@@ -2591,10 +2596,12 @@
     }
 
     @Override
+    @NonNull
     public Account[] getAccountsAsUser(String type, int userId, String opPackageName) {
         return getAccountsAsUser(type, userId, null, -1, opPackageName);
     }
 
+    @NonNull
     private Account[] getAccountsAsUser(
             String type,
             int userId,
@@ -2649,6 +2656,7 @@
         }
     }
 
+    @NonNull
     private Account[] getAccountsInternal(
             UserAccounts userAccounts,
             int callingUid,
@@ -2672,7 +2680,15 @@
     }
 
     @Override
-    public boolean addSharedAccountAsUser(Account account, int userId) {
+    public void addSharedAccountsFromParentUser(int parentUserId, int userId) {
+        checkManageUsersPermission("addSharedAccountsFromParentUser");
+        Account[] accounts = getAccountsAsUser(null, parentUserId, mContext.getOpPackageName());
+        for (Account account : accounts) {
+            addSharedAccountAsUser(account, userId);
+        }
+    }
+
+    private boolean addSharedAccountAsUser(Account account, int userId) {
         userId = handleIncomingUser(userId);
         UserAccounts accounts = getUserAccounts(userId);
         SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
@@ -2764,11 +2780,13 @@
     }
 
     @Override
+    @NonNull
     public Account[] getAccounts(String type, String opPackageName) {
         return getAccountsAsUser(type, UserHandle.getCallingUserId(), opPackageName);
     }
 
     @Override
+    @NonNull
     public Account[] getAccountsForPackage(String packageName, int uid, String opPackageName) {
         int callingUid = Binder.getCallingUid();
         if (!UserHandle.isSameApp(callingUid, Process.myUid())) {
@@ -2780,6 +2798,7 @@
     }
 
     @Override
+    @NonNull
     public Account[] getAccountsByTypeForPackage(String type, String packageName,
             String opPackageName) {
         int packageUid = -1;
@@ -3844,6 +3863,14 @@
         return false;
     }
 
+    private static void checkManageUsersPermission(String message) {
+        if (ActivityManager.checkComponentPermission(
+                android.Manifest.permission.MANAGE_USERS, Binder.getCallingUid(), -1, true)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("You need MANAGE_USERS permission to: " + message);
+        }
+    }
+
     private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
             int callerUid) {
         if (callerUid == Process.SYSTEM_UID) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index f5df9c3..bd10c63 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -994,6 +994,8 @@
      */
     int mConfigurationSeq = 0;
 
+    boolean mSuppressResizeConfigChanges = false;
+
     /**
      * Hardware-reported OpenGLES version.
      */
@@ -2021,7 +2023,7 @@
                                 intent, PendingIntent.FLAG_CANCEL_CURRENT, null,
                                 new UserHandle(userId)))
                         .setDeleteIntent(PendingIntent.getBroadcastAsUser(mContext, 0,
-                                deleteIntent, 0, UserHandle.OWNER))
+                                deleteIntent, 0, UserHandle.SYSTEM))
                         .build();
 
                 try {
@@ -2379,8 +2381,8 @@
         mGrantFile = new AtomicFile(new File(systemDir, "urigrants.xml"));
 
         // User 0 is the first and only user that runs at boot.
-        mStartedUsers.put(UserHandle.USER_OWNER, new UserState(UserHandle.OWNER, true));
-        mUserLru.add(UserHandle.USER_OWNER);
+        mStartedUsers.put(UserHandle.USER_SYSTEM, new UserState(UserHandle.SYSTEM, true));
+        mUserLru.add(UserHandle.USER_SYSTEM);
         updateStartedUserArrayLocked();
 
         GL_ES_VERSION = SystemProperties.getInt("ro.opengles.version",
@@ -5647,7 +5649,7 @@
                 try {
                     // Entire package setting changed
                     enabled = pm.getApplicationEnabledSetting(packageName,
-                            (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER);
+                            (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM);
                 } catch (Exception e) {
                     // No such package/component; probably racing with uninstall.  In any
                     // event it means we have nothing further to do here.
@@ -5665,7 +5667,7 @@
                 try {
                     enabled = pm.getComponentEnabledSetting(
                             new ComponentName(packageName, changedClass),
-                            (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_OWNER);
+                            (userId != UserHandle.USER_ALL) ? userId : UserHandle.USER_SYSTEM);
                 } catch (Exception e) {
                     // As above, probably racing with uninstall.
                     return;
@@ -9392,7 +9394,7 @@
                     (ProviderInfo)providers.get(i);
                 boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                         cpi.name, cpi.flags);
-                if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_OWNER) {
+                if (singleton && UserHandle.getUserId(app.uid) != UserHandle.USER_SYSTEM) {
                     // This is a singleton provider, but a user besides the
                     // default user is asking to initialize a process it runs
                     // in...  well, no, it doesn't actually run in this process,
@@ -9614,7 +9616,7 @@
         }
     }
 
-    private final ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
+    private ContentProviderHolder getContentProviderImpl(IApplicationThread caller,
             String name, IBinder token, boolean stable, int userId) {
         ContentProviderRecord cpr;
         ContentProviderConnection conn = null;
@@ -9642,14 +9644,14 @@
             cpr = mProviderMap.getProviderByName(name, userId);
             // If that didn't work, check if it exists for user 0 and then
             // verify that it's a singleton provider before using it.
-            if (cpr == null && userId != UserHandle.USER_OWNER) {
-                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_OWNER);
+            if (cpr == null && userId != UserHandle.USER_SYSTEM) {
+                cpr = mProviderMap.getProviderByName(name, UserHandle.USER_SYSTEM);
                 if (cpr != null) {
                     cpi = cpr.info;
                     if (isSingleton(cpi.processName, cpi.applicationInfo,
                             cpi.name, cpi.flags)
                             && isValidSingletonCall(r.uid, cpi.applicationInfo.uid)) {
-                        userId = UserHandle.USER_OWNER;
+                        userId = UserHandle.USER_SYSTEM;
                         checkCrossUser = false;
                     } else {
                         cpr = null;
@@ -9742,7 +9744,6 @@
                 Binder.restoreCallingIdentity(origId);
             }
 
-            boolean singleton;
             if (!providerRunning) {
                 try {
                     checkTime(startTime, "getContentProviderImpl: before resolveContentProvider");
@@ -9759,11 +9760,11 @@
                 // (it's a call within the same user || the provider is a
                 // privileged app)
                 // Then allow connecting to the singleton provider
-                singleton = isSingleton(cpi.processName, cpi.applicationInfo,
+                boolean singleton = isSingleton(cpi.processName, cpi.applicationInfo,
                         cpi.name, cpi.flags)
                         && isValidSingletonCall(r.uid, cpi.applicationInfo.uid);
                 if (singleton) {
-                    userId = UserHandle.USER_OWNER;
+                    userId = UserHandle.USER_SYSTEM;
                 }
                 cpi.applicationInfo = getAppInfoForUser(cpi.applicationInfo, userId);
                 checkTime(startTime, "getContentProviderImpl: got app info for user");
@@ -10366,7 +10367,7 @@
         }
         final ProcessRecord r = new ProcessRecord(stats, info, proc, uid);
         if (!mBooted && !mBooting
-                && userId == UserHandle.USER_OWNER
+                && userId == UserHandle.USER_SYSTEM
                 && (info.flags & PERSISTENT_MASK) == PERSISTENT_MASK) {
             r.persistent = true;
         }
@@ -11823,12 +11824,12 @@
     }
 
     private boolean deliverPreBootCompleted(final Runnable onFinishCallback,
-            ArrayList<ComponentName> doneReceivers, int userId) {
+            ArrayList<ComponentName> doneReceivers) {
         Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED);
         List<ResolveInfo> ris = null;
         try {
             ris = AppGlobals.getPackageManager().queryIntentReceivers(
-                    intent, null, 0, userId);
+                    intent, null, 0, UserHandle.USER_SYSTEM);
         } catch (RemoteException e) {
         }
         if (ris == null) {
@@ -11842,22 +11843,18 @@
         }
         intent.addFlags(Intent.FLAG_RECEIVER_BOOT_UPGRADE);
 
-        // For User 0, load the version number. When delivering to a new user, deliver
-        // to all receivers.
-        if (userId == UserHandle.USER_OWNER) {
-            ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
-            for (int i=0; i<ris.size(); i++) {
-                ActivityInfo ai = ris.get(i).activityInfo;
-                ComponentName comp = new ComponentName(ai.packageName, ai.name);
-                if (lastDoneReceivers.contains(comp)) {
-                    // We already did the pre boot receiver for this app with the current
-                    // platform version, so don't do it again...
-                    ris.remove(i);
-                    i--;
-                    // ...however, do keep it as one that has been done, so we don't
-                    // forget about it when rewriting the file of last done receivers.
-                    doneReceivers.add(comp);
-                }
+        ArrayList<ComponentName> lastDoneReceivers = readLastDonePreBootReceivers();
+        for (int i=0; i<ris.size(); i++) {
+            ActivityInfo ai = ris.get(i).activityInfo;
+            ComponentName comp = new ComponentName(ai.packageName, ai.name);
+            if (lastDoneReceivers.contains(comp)) {
+                // We already did the pre boot receiver for this app with the current
+                // platform version, so don't do it again...
+                ris.remove(i);
+                i--;
+                // ...however, do keep it as one that has been done, so we don't
+                // forget about it when rewriting the file of last done receivers.
+                doneReceivers.add(comp);
             }
         }
 
@@ -11865,9 +11862,8 @@
             return false;
         }
 
-        // If primary user, send broadcast to all available users, else just to userId
-        final int[] users = userId == UserHandle.USER_OWNER ? getUsersLocked()
-                : new int[] { userId };
+        // TODO: can we still do this with per user encryption?
+        final int[] users = getUsersLocked();
         if (users.length <= 0) {
             return false;
         }
@@ -11918,7 +11914,7 @@
                         writeLastDonePreBootReceivers(doneReceivers);
                         systemReady(goingCallback);
                     }
-                }, doneReceivers, UserHandle.USER_OWNER);
+                }, doneReceivers);
 
                 if (mWaitingUpdate) {
                     return;
@@ -17521,6 +17517,15 @@
     }
 
     @Override
+    public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "suppressResizeConfigChanges()");
+        synchronized (this) {
+            mSuppressResizeConfigChanges = suppress;
+        }
+    }
+
+    @Override
     public void updatePersistentConfiguration(Configuration values) {
         enforceCallingPermission(android.Manifest.permission.CHANGE_CONFIGURATION,
                 "updateConfiguration()");
@@ -20172,7 +20177,7 @@
                 }
 
                 if ((userInfo.flags&UserInfo.FLAG_INITIALIZED) == 0) {
-                    if (userId != UserHandle.USER_OWNER) {
+                    if (userId != UserHandle.USER_SYSTEM) {
                         Intent intent = new Intent(Intent.ACTION_USER_INITIALIZE);
                         intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
                         broadcastIntentLocked(null, null, intent, null,
@@ -20410,7 +20415,7 @@
             for (int i = 0; i < num; i++) {
                 Integer oldUserId = mUserLru.get(i);
                 UserState oldUss = mStartedUsers.get(oldUserId);
-                if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId
+                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId
                         || oldUss.mState == UserState.STATE_STOPPING
                         || oldUss.mState == UserState.STATE_SHUTDOWN) {
                     continue;
@@ -20495,8 +20500,12 @@
                     i++;
                     continue;
                 }
-                if (oldUserId == UserHandle.USER_OWNER || oldUserId == mCurrentUserId) {
-                    // Owner and current can't be stopped, but count as running.
+                if (oldUserId == UserHandle.USER_SYSTEM || oldUserId == mCurrentUserId) {
+                    // Owner/System user and current user can't be stopped. We count it as running
+                    // when it is not a pure system user.
+                    if (UserInfo.isSystemOnly(oldUserId)) {
+                        num--;
+                    }
                     i++;
                     continue;
                 }
@@ -20519,8 +20528,8 @@
             Slog.w(TAG, msg);
             throw new SecurityException(msg);
         }
-        if (userId < 0 || userId == UserHandle.USER_OWNER) {
-            throw new IllegalArgumentException("Can't stop primary user " + userId);
+        if (userId < 0 || userId == UserHandle.USER_SYSTEM) {
+            throw new IllegalArgumentException("Can't stop system user " + userId);
         }
         enforceShellRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userId);
         synchronized (this) {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index cf4a25e..a796ea7 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -529,21 +529,15 @@
      * */
     void moveToFront(String reason, TaskRecord task) {
         if (isAttached()) {
-            final boolean homeStack = isHomeStack()
-                    || (mActivityContainer.mParentActivity != null
-                        && mActivityContainer.mParentActivity.isHomeActivity());
-            ActivityStack lastFocusStack = null;
-            if (!homeStack) {
-                // Need to move this stack to the front before calling
-                // {@link ActivityStackSupervisor#moveHomeStack} below.
-                lastFocusStack = mStacks.get(mStacks.size() - 1);
-                mStacks.remove(this);
-                mStacks.add(this);
-            }
-            // TODO(multi-display): Focus stack currently adjusted in call to move home stack.
-            // Needs to also work if focus is moving to the non-home display.
+            final ActivityStack lastFocusStack = mStacks.get(mStacks.size() - 1);
+            // Need to move this stack to the front before calling
+            // {@link ActivityStackSupervisor#setFocusStack} below.
+            mStacks.remove(this);
+            mStacks.add(this);
+
+            // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
             if (isOnHomeDisplay()) {
-                mStackSupervisor.moveHomeStack(homeStack, reason, lastFocusStack);
+                mStackSupervisor.setFocusStack(reason, lastFocusStack);
             }
             if (task != null) {
                 insertTaskAtTop(task, null);
@@ -1336,17 +1330,28 @@
             return topHomeActivity == null || !topHomeActivity.isHomeActivity();
         }
 
-        if (focusedStackId == DOCKED_STACK_ID
-                && stackIndex == (mStacks.indexOf(focusedStack) - 1)) {
+        final int belowFocusedIndex = mStacks.indexOf(focusedStack) - 1;
+        if (focusedStackId == DOCKED_STACK_ID && stackIndex == belowFocusedIndex) {
             // Stacks directly behind the docked stack are always visible.
             return true;
         }
 
-        if (mStackId == HOME_STACK_ID && focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID) {
-            // Home stack is always visible behind the fullscreen stack with a translucent activity.
-            // This is done so that the home stack can act as a background to the translucent
-            // activity.
-            return hasTranslucentActivity(focusedStack);
+        if (focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
+                && hasTranslucentActivity(focusedStack)) {
+            // Stacks behind the fullscreen stack with a translucent activity are always
+            // visible so they can act as a backdrop to the translucent activity.
+            // For example, dialog activities
+            if (stackIndex == belowFocusedIndex) {
+                return true;
+            }
+            if (belowFocusedIndex >= 0) {
+                final ActivityStack stack = mStacks.get(belowFocusedIndex);
+                if (stack.mStackId == DOCKED_STACK_ID && stackIndex == (belowFocusedIndex - 1)) {
+                    // The stack behind the docked stack is also visible so we can have a complete
+                    // backdrop to the translucent activity when the docked stack is up.
+                    return true;
+                }
+            }
         }
 
         if (mStackId >= FIRST_STATIC_STACK_ID && mStackId <= LAST_STATIC_STACK_ID) {
@@ -1952,7 +1957,6 @@
                             ? AppTransition.TRANSIT_ACTIVITY_CLOSE
                             : AppTransition.TRANSIT_TASK_CLOSE, false);
                 }
-                mWindowManager.setAppWillBeHidden(prev.appToken);
                 mWindowManager.setAppVisibility(prev.appToken, false);
             } else {
                 if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION,
@@ -1968,10 +1972,6 @@
                                     : AppTransition.TRANSIT_TASK_OPEN, false);
                 }
             }
-            if (false) {
-                mWindowManager.setAppWillBeHidden(prev.appToken);
-                mWindowManager.setAppVisibility(prev.appToken, false);
-            }
         } else {
             if (DEBUG_TRANSITION) Slog.v(TAG_TRANSITION, "Prepare open transition: no previous");
             if (mNoAnimActivities.contains(next)) {
@@ -4176,8 +4176,12 @@
                 | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) == 0;
     }
 
-    private boolean relaunchActivityLocked(ActivityRecord r, int changes, boolean andResume,
-            boolean preserveWindow) {
+    private void relaunchActivityLocked(
+            ActivityRecord r, int changes, boolean andResume, boolean preserveWindow) {
+        if (mService.mSuppressResizeConfigChanges && preserveWindow) {
+            return;
+        }
+
         List<ResultInfo> results = null;
         List<ReferrerIntent> newIntents = null;
         if (andResume) {
@@ -4217,8 +4221,6 @@
             mHandler.removeMessages(PAUSE_TIMEOUT_MSG, r);
             r.state = ActivityState.PAUSED;
         }
-
-        return true;
     }
 
     boolean willActivityBeVisibleLocked(IBinder token) {
@@ -4543,18 +4545,17 @@
 
         if (mTaskHistory.isEmpty()) {
             if (DEBUG_STACK) Slog.i(TAG_STACK, "removeTask: removing stack=" + this);
-            final boolean notHomeStack = !isHomeStack();
             if (isOnHomeDisplay()) {
                 String myReason = reason + " leftTaskHistoryEmpty";
                 if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
-                    mStackSupervisor.moveHomeStack(notHomeStack, myReason);
+                    mStackSupervisor.moveHomeStackToFront(myReason);
                 }
             }
             if (mStacks != null) {
                 mStacks.remove(this);
                 mStacks.add(0, this);
             }
-            if (notHomeStack) {
+            if (!isHomeStack()) {
                 mActivityContainer.onTaskListEmptyLocked();
             }
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 8c856a8..6b5f205 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -24,6 +24,7 @@
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
 import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
 import static com.android.server.am.ActivityManagerDebugConfig.*;
 import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
 import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
@@ -87,6 +88,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.TransactionTooLargeException;
 import android.os.UserHandle;
 import android.os.WorkSource;
@@ -468,35 +470,22 @@
         return stack == mFocusedStack;
     }
 
-    void moveHomeStack(boolean toFront, String reason) {
-        moveHomeStack(toFront, reason, null);
-    }
-
-    void moveHomeStack(boolean toFront, String reason, ActivityStack lastFocusedStack) {
+    void setFocusStack(String reason, ActivityStack lastFocusedStack) {
         ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
         final int topNdx = stacks.size() - 1;
         if (topNdx <= 0) {
             return;
         }
 
-        // The home stack should either be at the top or bottom of the stack list.
-        if ((toFront && (stacks.get(topNdx) != mHomeStack))
-                || (!toFront && (stacks.get(0) != mHomeStack))) {
-            if (DEBUG_STACK) Slog.d(TAG_STACK, "moveHomeTask: topStack old="
-                    + ((lastFocusedStack != null) ? lastFocusedStack : stacks.get(topNdx))
-                    + " new=" + mFocusedStack);
-            stacks.remove(mHomeStack);
-            stacks.add(toFront ? topNdx : 0, mHomeStack);
-        }
-
+        final ActivityStack topStack = stacks.get(topNdx);
+        mFocusedStack = topStack;
         if (lastFocusedStack != null) {
             mLastFocusedStack = lastFocusedStack;
         }
-        mFocusedStack = stacks.get(topNdx);
 
-        EventLog.writeEvent(EventLogTags.AM_HOME_STACK_MOVED,
-                mCurrentUser, toFront ? 1 : 0, stacks.get(topNdx).getStackId(),
-                mFocusedStack == null ? -1 : mFocusedStack.getStackId(), reason);
+        EventLogTags.writeAmFocusedStack(
+                mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+                mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
 
         if (mService.mBooting || !mService.mBooted) {
             final ActivityRecord r = topRunningActivityLocked();
@@ -506,6 +495,10 @@
         }
     }
 
+    void moveHomeStackToFront(String reason) {
+        mHomeStack.moveToFront(reason);
+    }
+
     /** Returns true if the focus activity was adjusted to the home stack top activity. */
     boolean moveHomeStackTaskToTop(int homeStackTaskType, String reason) {
         if (homeStackTaskType == RECENTS_ACTIVITY_TYPE) {
@@ -1357,8 +1350,7 @@
 
         r.launchFailed = false;
         if (stack.updateLRUListLocked(r)) {
-            Slog.w(TAG, "Activity " + r
-                  + " being launched, but already in LRU list");
+            Slog.w(TAG, "Activity " + r + " being launched, but already in LRU list");
         }
 
         if (andResume) {
@@ -1807,8 +1799,11 @@
                 return container.mStack;
             }
 
-            if (mFocusedStack != mHomeStack && (!newTask ||
-                    mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
+            // The fullscreen stack is the only stack that can contain any task regardless of if
+            // the task is resizeable or not. So, we let the task go in the fullscreen task if it
+            // is the focus stack.
+            if (mFocusedStack.mStackId == FULLSCREEN_WORKSPACE_STACK_ID
+                    && (!newTask || mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
                 if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
                         "computeStackFocus: Have a focused stack=" + mFocusedStack);
                 return mFocusedStack;
@@ -1827,7 +1822,7 @@
             }
 
             // If there is no suitable dynamic stack then we figure out which static stack to use.
-            int stackId = task != null ? task.getLaunchStackId() :
+            final int stackId = task != null ? task.getLaunchStackId() :
                         bounds != null ? FREEFORM_WORKSPACE_STACK_ID :
                                          FULLSCREEN_WORKSPACE_STACK_ID;
             stack = getStack(stackId, CREATE_IF_NEEDED, ON_TOP);
@@ -2974,6 +2969,8 @@
             return;
         }
 
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
+
         ActivityRecord r = stack.topRunningActivityLocked(null);
 
         mTmpBounds.clear();
@@ -3057,6 +3054,8 @@
                 resumeTopActivitiesLocked(stack, null, null);
             }
         }
+
+        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode) {
@@ -3085,6 +3084,8 @@
             return;
         }
 
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeTask_" + task.taskId);
+
         // The stack of a task is determined by its size (fullscreen vs non-fullscreen).
         // Place the task in the right stack if it isn't there already based on the requested
         // bounds.
@@ -3109,27 +3110,20 @@
             ActivityRecord r = task.topRunningActivityLocked(null);
             if (r != null) {
                 final ActivityStack stack = task.stack;
-                final boolean resizedByUser = resizeMode == RESIZE_MODE_USER;
-                final boolean preserveWindow = resizedByUser && !changedStacks;
+                final boolean preserveWindow = !changedStacks &&
+                        (resizeMode == RESIZE_MODE_USER
+                        || resizeMode == RESIZE_MODE_SYSTEM_SCREEN_ROTATION);
                 kept = stack.ensureActivityConfigurationLocked(r, 0, preserveWindow);
                 // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
                 if (!kept) {
                     resumeTopActivitiesLocked(stack, null, null);
-                    if (changedStacks && stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
-                        // We are about to relaunch the activity because its configuration changed
-                        // due to being maximized, i.e. size change. The activity will first
-                        // remove the old window and then add a new one. This call will tell window
-                        // manager about this, so it can preserve the old window until the new
-                        // one is drawn. This prevents having a gap between the removal and
-                        // addition, in which no window is visible. We also want the entrace of the
-                        // new window to be properly animated.
-                        mWindowManager.setReplacingWindow(r.appToken, true /* animate */);
-                    }
                 }
             }
         }
         mWindowManager.resizeTask(task.taskId, bounds, task.mOverrideConfig, kept, forced);
+
+        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
     }
 
     ActivityStack createStackOnDisplay(int stackId, int displayId, boolean onTop) {
@@ -3216,7 +3210,13 @@
         final boolean wasFocused = isFrontStack(task.stack) && (topRunningActivityLocked() == r);
         final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
 
+        final boolean resizeable = task.mResizeable;
+        // Temporarily disable resizeablility of task we are moving. We don't want it to be resized
+        // if a docked stack is created below which will lead to the stack we are moving from and
+        // its resizeable tasks being resized.
+        task.mResizeable = false;
         final ActivityStack stack = getStack(stackId, CREATE_IF_NEEDED, toTop);
+        task.mResizeable = resizeable;
         mWindowManager.moveTaskToStack(task.taskId, stack.mStackId, toTop);
         if (task.stack != null) {
             task.stack.removeTask(task, reason, MOVING);
@@ -3246,6 +3246,16 @@
             return;
         }
         final String reason = "moveTaskToStack";
+        if (stackId == DOCKED_STACK_ID || stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+            // We are about to relaunch the activity because its configuration changed due to
+            // being maximized, i.e. size change. The activity will first remove the old window
+            // and then add a new one. This call will tell window manager about this, so it can
+            // preserve the old window until the new one is drawn. This prevents having a gap
+            // between the removal and addition, in which no window is visible. We also want the
+            // entrace of the new window to be properly animated.
+            ActivityRecord r = task.getTopActivity();
+            mWindowManager.setReplacingWindow(r.appToken, true /* animate */);
+        }
         final ActivityStack stack =
                 moveTaskToStackUncheckedLocked(task, stackId, toTop, forceFocus, reason);
 
@@ -3657,11 +3667,7 @@
         }
         final boolean homeInFront = stack.isHomeStack();
         if (stack.isOnHomeDisplay()) {
-            moveHomeStack(homeInFront, "switchUserOnHomeDisplay");
-            TaskRecord task = stack.topTask();
-            if (task != null) {
-                mWindowManager.moveTaskToTop(task.taskId);
-            }
+            stack.moveToFront("switchUserOnHomeDisplay");
         } else {
             // Stack was moved to another display while user was swapped out.
             resumeHomeStackTask(HOME_ACTIVITY_TYPE, null, "switchUserOnOtherDisplay");
@@ -4621,16 +4627,6 @@
             return mActivityDisplay != null;
         }
 
-        void getBounds(Point outBounds) {
-            synchronized (mService) {
-                    if (mActivityDisplay != null) {
-                    mActivityDisplay.getBounds(outBounds);
-                } else {
-                    outBounds.set(0, 0);
-                }
-            }
-        }
-
         // TODO: Make sure every change to ActivityRecord.visible results in a call to this.
         void setVisible(boolean visible) {
             if (mVisible != visible) {
@@ -4802,12 +4798,6 @@
             mStacks.remove(stack);
         }
 
-        void getBounds(Point bounds) {
-            mDisplay.getDisplayInfo(mDisplayInfo);
-            bounds.x = mDisplayInfo.appWidth;
-            bounds.y = mDisplayInfo.appHeight;
-        }
-
         void setVisibleBehindActivity(ActivityRecord r) {
             mVisibleBehindActivity = r;
         }
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 9a645df..78b5f33 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -93,8 +93,8 @@
 # Activity focused
 30043 am_focused_activity (User|1|5),(Component Name|3)
 
-# Home Stack brought to front or rear
-30044 am_home_stack_moved (User|1|5),(To Front|1|5),(Top Stack Id|1|5),(Focused Stack Id|1|5),(Reason|3)
+# Stack focus
+30044 am_focused_stack (User|1|5),(Focused Stack Id|1|5),(Last Focused Stack Id|1|5),(Reason|3)
 
 # Running pre boot receiver
 30045 am_pre_boot (User|1|5),(Package|3)
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 43f5baa..7e14b2b 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -1193,7 +1193,7 @@
             mOverrideConfig = Configuration.EMPTY;
         } else {
             mBounds = new Rect(bounds);
-            if (stack.mStackId != DOCKED_STACK_ID) {
+            if (stack == null || stack.mStackId != DOCKED_STACK_ID) {
                 mLastNonFullscreenBounds = mBounds;
             }
 
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 99ca050..e49a7e4 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -2524,11 +2524,14 @@
     }
 
     /** @see AudioManager#setBluetoothScoOn(boolean) */
-    public void setBluetoothScoOn(boolean on){
+    public void setBluetoothScoOn(boolean on) {
         if (!checkAudioSettingsPermission("setBluetoothScoOn()")) {
             return;
         }
+        setBluetoothScoOnInt(on);
+    }
 
+    public void setBluetoothScoOnInt(boolean on) {
         if (on) {
             mForcedUseForComm = AudioSystem.FORCE_BT_SCO;
         } else if (mForcedUseForComm == AudioSystem.FORCE_BT_SCO) {
@@ -2889,6 +2892,8 @@
             mScoAudioState = SCO_STATE_INACTIVE;
             broadcastScoConnectionState(AudioManager.SCO_AUDIO_STATE_DISCONNECTED);
         }
+        AudioSystem.setParameters("A2dpSuspended=false");
+        setBluetoothScoOnInt(false);
     }
 
     private void broadcastScoConnectionState(int state) {
diff --git a/services/core/java/com/android/server/connectivity/Vpn.java b/services/core/java/com/android/server/connectivity/Vpn.java
index 3df3cd0..2bea278 100644
--- a/services/core/java/com/android/server/connectivity/Vpn.java
+++ b/services/core/java/com/android/server/connectivity/Vpn.java
@@ -20,9 +20,6 @@
 import static android.net.ConnectivityManager.NETID_UNSET;
 import static android.net.RouteInfo.RTN_THROW;
 import static android.net.RouteInfo.RTN_UNREACHABLE;
-import static android.os.UserHandle.PER_USER_RANGE;
-import static android.system.OsConstants.AF_INET;
-import static android.system.OsConstants.AF_INET6;
 
 import android.Manifest;
 import android.app.AppGlobals;
@@ -34,13 +31,11 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.pm.UserInfo;
 import android.net.ConnectivityManager;
-import android.net.IConnectivityManager;
 import android.net.INetworkManagementEventObserver;
 import android.net.IpPrefix;
 import android.net.LinkAddress;
@@ -126,7 +121,6 @@
     /* list of users using this VPN. */
     @GuardedBy("this")
     private List<UidRange> mVpnUsers = null;
-    private BroadcastReceiver mUserIntentReceiver = null;
 
     // Handle of user initiating VPN.
     private final int mUserHandle;
@@ -146,31 +140,6 @@
         } catch (RemoteException e) {
             Log.wtf(TAG, "Problem registering observer", e);
         }
-        // TODO: http://b/22950929
-        if (userHandle == UserHandle.USER_SYSTEM) {
-            // Owner's VPN also needs to handle restricted users
-            mUserIntentReceiver = new BroadcastReceiver() {
-                @Override
-                public void onReceive(Context context, Intent intent) {
-                    final String action = intent.getAction();
-                    final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE,
-                            UserHandle.USER_NULL);
-                    if (userHandle == UserHandle.USER_NULL) return;
-
-                    if (Intent.ACTION_USER_ADDED.equals(action)) {
-                        onUserAdded(userHandle);
-                    } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
-                        onUserRemoved(userHandle);
-                    }
-                }
-            };
-
-            IntentFilter intentFilter = new IntentFilter();
-            intentFilter.addAction(Intent.ACTION_USER_ADDED);
-            intentFilter.addAction(Intent.ACTION_USER_REMOVED);
-            mContext.registerReceiverAsUser(
-                    mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
-        }
 
         mNetworkInfo = new NetworkInfo(ConnectivityManager.TYPE_VPN, 0, NETWORKTYPE, "");
         // TODO: Copy metered attribute and bandwidths from physical transport, b/16207332
@@ -439,8 +408,8 @@
         }
 
         addVpnUserLocked(mUserHandle);
-        // If we are owner assign all Restricted Users to this VPN
-        if (mUserHandle == UserHandle.USER_OWNER) {
+        // If the user can have restricted profiles, assign all its restricted profiles to this VPN
+        if (canHaveRestrictedProfile(mUserHandle)) {
             token = Binder.clearCallingIdentity();
             List<UserInfo> users;
             try {
@@ -449,7 +418,7 @@
                 Binder.restoreCallingIdentity(token);
             }
             for (UserInfo user : users) {
-                if (user.isRestricted()) {
+                if (user.isRestricted() && (user.restrictedProfileParentId == mUserHandle)) {
                     addVpnUserLocked(user.id);
                 }
             }
@@ -457,6 +426,15 @@
         mNetworkAgent.addUidRanges(mVpnUsers.toArray(new UidRange[mVpnUsers.size()]));
     }
 
+    private boolean canHaveRestrictedProfile(int userId) {
+        long token = Binder.clearCallingIdentity();
+        try {
+            return UserManager.get(mContext).canHaveRestrictedProfile(userId);
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
+    }
+
     private void agentDisconnect(NetworkInfo networkInfo, NetworkAgent networkAgent) {
         networkInfo.setIsAvailable(false);
         networkInfo.setDetailedState(DetailedState.DISCONNECTED, null, null);
@@ -681,12 +659,11 @@
         mStatusIntent = null;
     }
 
-    private void onUserAdded(int userHandle) {
-        // If the user is restricted tie them to the owner's VPN
-        synchronized(Vpn.this) {
-            UserManager mgr = UserManager.get(mContext);
-            UserInfo user = mgr.getUserInfo(userHandle);
-            if (user.isRestricted()) {
+    public void onUserAdded(int userHandle) {
+        // If the user is restricted tie them to the parent user's VPN
+        UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
+        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+            synchronized(Vpn.this) {
                 try {
                     addVpnUserLocked(userHandle);
                     if (mNetworkAgent != null) {
@@ -700,12 +677,11 @@
         }
     }
 
-    private void onUserRemoved(int userHandle) {
+    public void onUserRemoved(int userHandle) {
         // clean up if restricted
-        synchronized(Vpn.this) {
-            UserManager mgr = UserManager.get(mContext);
-            UserInfo user = mgr.getUserInfo(userHandle);
-            if (user.isRestricted()) {
+        UserInfo user = UserManager.get(mContext).getUserInfo(userHandle);
+        if (user.isRestricted() && user.restrictedProfileParentId == mUserHandle) {
+            synchronized(Vpn.this) {
                 try {
                     removeVpnUserLocked(userHandle);
                 } catch (Exception e) {
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 533f425..452378ff 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -837,7 +837,6 @@
         if (mPendingScreenOff && target != Display.STATE_OFF) {
             setScreenState(Display.STATE_OFF);
             mPendingScreenOff = false;
-            mPowerState.dismissColorFade();
         }
 
         if (target == Display.STATE_ON) {
@@ -911,7 +910,6 @@
                 // A black surface is already hiding the contents of the screen.
                 setScreenState(Display.STATE_OFF);
                 mPendingScreenOff = false;
-                mPowerState.dismissColorFade();
             } else if (performScreenOffTransition
                     && mPowerState.prepareColorFade(mContext,
                             mColorFadeFadesConfig ?
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index be37f52..088d96e 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -544,7 +544,7 @@
                     physIndex = findDisplayInfoIndexLocked(colorTransformId, modeId);
                 }
             }
-            if (physIndex > 0 && mActivePhysIndex == physIndex) {
+            if (mActivePhysIndex == physIndex) {
                 return;
             }
             SurfaceControl.setActiveConfig(getDisplayTokenLocked(), physIndex);
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 0c884f15..7b15aad 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -27,6 +27,7 @@
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.AppOpsManager;
+import android.app.AutomaticZenRule;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
 import android.app.ITransientNotification;
@@ -101,6 +102,7 @@
 import com.android.internal.R;
 import com.android.internal.statusbar.NotificationVisibility;
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.Preconditions;
 import com.android.server.EventLogTags;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -1172,8 +1174,8 @@
             // Don't allow client applications to cancel foreground service notis.
             cancelNotification(Binder.getCallingUid(), Binder.getCallingPid(), pkg, tag, id, 0,
                     Binder.getCallingUid() == Process.SYSTEM_UID
-                    ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId, REASON_NOMAN_CANCEL,
-                    null);
+                            ? 0 : Notification.FLAG_FOREGROUND_SERVICE, false, userId,
+                    REASON_NOMAN_CANCEL, null);
         }
 
         @Override
@@ -1594,6 +1596,50 @@
         }
 
         @Override
+        public List<AutomaticZenRule> getAutomaticZenRules() throws RemoteException {
+            enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRules");
+            return mZenModeHelper.getAutomaticZenRules();
+        }
+
+        @Override
+        public AutomaticZenRule getAutomaticZenRule(String name) throws RemoteException {
+            enforcePolicyAccess(Binder.getCallingUid(), "getAutomaticZenRule");
+            return mZenModeHelper.getAutomaticZenRule(name);
+        }
+
+        @Override
+        public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule)
+                throws RemoteException {
+            Preconditions.checkNotNull(automaticZenRule, "automaticZenRule is null");
+            Preconditions.checkNotNull(automaticZenRule.getName(), "Name is null");
+            Preconditions.checkNotNull(automaticZenRule.getOwner(), "Owner is null");
+            Preconditions.checkNotNull(automaticZenRule.getConditionId(), "ConditionId is null");
+            enforcePolicyAccess(Binder.getCallingUid(), "addOrUpdateZenModeRule");
+
+            return mZenModeHelper.addOrUpdateAutomaticZenRule(automaticZenRule,
+                    "addOrUpdateAutomaticZenRule");
+        }
+
+        @Override
+        public boolean renameAutomaticZenRule(String oldName, String newName) {
+            Preconditions.checkNotNull(oldName, "oldName is null");
+            Preconditions.checkNotNull(newName, "newName is null");
+            enforcePolicyAccess(Binder.getCallingUid(), "renameAutomaticZenRule");
+
+            return mZenModeHelper.renameAutomaticZenRule(
+                    oldName, newName, "renameAutomaticZenRule");
+        }
+
+        @Override
+        public boolean removeAutomaticZenRule(String name) throws RemoteException {
+            Preconditions.checkNotNull(name, "Name is null");
+            // Verify that they can modify zen rules.
+            enforcePolicyAccess(Binder.getCallingUid(), "removeAutomaticZenRule");
+
+            return mZenModeHelper.removeAutomaticZenRule(name, "removeAutomaticZenRule");
+        }
+
+        @Override
         public void setInterruptionFilter(String pkg, int filter) throws RemoteException {
             enforcePolicyAccess(pkg, "setInterruptionFilter");
             final int zen = NotificationManager.zenModeFromInterruptionFilter(filter, -1);
@@ -1641,7 +1687,30 @@
                     message);
         }
 
+        private void enforcePolicyAccess(int uid, String method) {
+            if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
+                    android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
+                return;
+            }
+            boolean accessAllowed = false;
+            String[] packages = getContext().getPackageManager().getPackagesForUid(uid);
+            final int packageCount = packages.length;
+            for (int i = 0; i < packageCount; i++) {
+                if (checkPolicyAccess(packages[i])) {
+                    accessAllowed = true;
+                }
+            }
+            if (!accessAllowed) {
+                Slog.w(TAG, "Notification policy access denied calling " + method);
+                throw new SecurityException("Notification policy access denied");
+            }
+        }
+
         private void enforcePolicyAccess(String pkg, String method) {
+            if (PackageManager.PERMISSION_GRANTED == getContext().checkCallingPermission(
+                    android.Manifest.permission.MANAGE_NOTIFICATIONS)) {
+                return;
+            }
             if (!checkPolicyAccess(pkg)) {
                 Slog.w(TAG, "Notification policy access denied calling " + method);
                 throw new SecurityException("Notification policy access denied");
@@ -1684,7 +1753,7 @@
         public boolean matchesCallFilter(Bundle extras) {
             enforceSystemOrSystemUI("INotificationManager.matchesCallFilter");
             return mZenModeHelper.matchesCallFilter(
-                    UserHandle.getCallingUserHandle(),
+                    Binder.getCallingUserHandle(),
                     extras,
                     mRankingHelper.findExtractor(ValidateNotificationPeople.class),
                     MATCHES_CALL_FILTER_CONTACTS_TIMEOUT_MS,
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index cbe61c3..4d41e3a 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -21,11 +21,13 @@
 import static android.media.AudioAttributes.USAGE_NOTIFICATION_RINGTONE;
 
 import android.app.AppOpsManager;
+import android.app.AutomaticZenRule;
 import android.app.NotificationManager;
 import android.app.NotificationManager.Policy;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.content.res.Resources;
 import android.content.res.XmlResourceParser;
 import android.database.ContentObserver;
@@ -34,6 +36,7 @@
 import android.media.AudioSystem;
 import android.media.VolumePolicy;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Looper;
@@ -62,6 +65,7 @@
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 import java.util.Objects;
 
 /**
@@ -196,6 +200,121 @@
         return mZenMode;
     }
 
+    public List<AutomaticZenRule> getAutomaticZenRules() {
+        List<AutomaticZenRule> rules = new ArrayList<>();
+        if (mConfig == null) return rules;
+        for(ZenRule rule : mConfig.automaticRules.values()) {
+            if (canManageAutomaticZenRule(rule)) {
+                rules.add(createAutomaticZenRule(rule));
+            }
+        }
+        return rules;
+    }
+
+    public AutomaticZenRule getAutomaticZenRule(String name) {
+        if (mConfig == null) return null;
+        for(ZenRule rule : mConfig.automaticRules.values()) {
+            if (canManageAutomaticZenRule(rule) && rule.name.equals(name)) {
+                return createAutomaticZenRule(rule);
+            }
+        }
+        return null;
+    }
+
+    public boolean addOrUpdateAutomaticZenRule(AutomaticZenRule automaticZenRule, String reason) {
+        if (mConfig == null) return false;
+        if (DEBUG) {
+            Log.d(TAG, "addOrUpdateAutomaticZenRule zenRule=" + automaticZenRule
+                    + " reason=" + reason);
+        }
+        final ZenModeConfig newConfig = mConfig.copy();
+        String ruleId = findMatchingRuleId(newConfig, automaticZenRule.getName());
+        ZenModeConfig.ZenRule rule = new ZenModeConfig.ZenRule();
+        if (ruleId == null) {
+            ruleId = newConfig.newRuleId();
+            rule.name = automaticZenRule.getName();
+            rule.component = automaticZenRule.getOwner();
+        } else {
+            rule = newConfig.automaticRules.get(ruleId);
+            if (!canManageAutomaticZenRule(rule)) {
+                throw new SecurityException(
+                        "Cannot update rules not owned by your condition provider");
+            }
+        }
+        if (rule.enabled != automaticZenRule.isEnabled()) {
+            rule.snoozing = false;
+        }
+        rule.condition = null;
+        rule.conditionId = automaticZenRule.getConditionId();
+        rule.enabled = automaticZenRule.isEnabled();
+        rule.zenMode = NotificationManager.zenModeFromInterruptionFilter(
+                automaticZenRule.getInterruptionFilter(), Global.ZEN_MODE_OFF);
+        newConfig.automaticRules.put(ruleId, rule);
+        return setConfig(newConfig, reason, true);
+    }
+
+    public boolean renameAutomaticZenRule(String oldName, String newName, String reason) {
+        if (mConfig == null) return false;
+        if (DEBUG) {
+            Log.d(TAG, "renameAutomaticZenRule oldName=" + oldName + "  newName=" + newName
+                    + " reason=" + reason);
+        }
+        final ZenModeConfig newConfig = mConfig.copy();
+        String ruleId = findMatchingRuleId(newConfig, oldName);
+        if (ruleId == null) {
+            return false;
+        } else {
+            ZenRule rule = newConfig.automaticRules.get(ruleId);
+            if (!canManageAutomaticZenRule(rule)) {
+                throw new SecurityException(
+                        "Cannot update rules not owned by your condition provider");
+            }
+            rule.name = newName;
+            return setConfig(newConfig, reason, true);
+        }
+    }
+
+    public boolean removeAutomaticZenRule(String name, String reason) {
+        if (mConfig == null) return false;
+        final ZenModeConfig newConfig = mConfig.copy();
+        String ruleId = findMatchingRuleId(newConfig, name);
+        if (ruleId != null) {
+            ZenRule rule = newConfig.automaticRules.get(ruleId);
+            if (canManageAutomaticZenRule(rule)) {
+                newConfig.automaticRules.remove(ruleId);
+                if (DEBUG) Log.d(TAG, "removeZenRule zenRule=" + name + " reason=" + reason);
+            } else {
+                throw new SecurityException(
+                        "Cannot delete rules not owned by your condition provider");
+            }
+        }
+        return setConfig(newConfig, reason, true);
+    }
+
+    public boolean canManageAutomaticZenRule(ZenRule rule) {
+        if (mContext.checkCallingPermission(android.Manifest.permission.MANAGE_NOTIFICATIONS)
+                == PackageManager.PERMISSION_GRANTED) {
+            return true;
+        } else {
+            String[] packages = mContext.getPackageManager().getPackagesForUid(
+                    Binder.getCallingUid());
+            if (packages != null) {
+                final int packageCount = packages.length;
+                for (int i = 0; i < packageCount; i++) {
+                    if (packages[i].equals(rule.component.getPackageName())) {
+                        return true;
+                    }
+                }
+            }
+            return false;
+        }
+    }
+
+    private AutomaticZenRule createAutomaticZenRule(ZenRule rule) {
+        return new AutomaticZenRule(rule.name, rule.component, rule.conditionId,
+                NotificationManager.zenModeToInterruptionFilter(rule.zenMode), rule.enabled);
+    }
+
     public void setManualZenMode(int zenMode, Uri conditionId, String reason) {
         setManualZenMode(zenMode, conditionId, reason, true /*setRingerMode*/);
     }
@@ -225,6 +344,15 @@
         setConfig(newConfig, reason, setRingerMode);
     }
 
+    private String findMatchingRuleId(ZenModeConfig config, String ruleName) {
+        for (String ruleId : config.automaticRules.keySet()) {
+            if (config.automaticRules.get(ruleId).name.equals(ruleName)) {
+                return ruleId;
+            }
+        }
+        return null;
+    }
+
     public void dump(PrintWriter pw, String prefix) {
         pw.print(prefix); pw.print("mZenMode=");
         pw.println(Global.zenModeToString(mZenMode));
@@ -248,8 +376,9 @@
         }
         pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
                 + "events=%s,reminders=%s)\n",
-                config.allowCalls, config.allowCallsFrom, config.allowRepeatCallers,
-                config.allowMessages, config.allowMessagesFrom,
+                config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
+                config.allowRepeatCallers, config.allowMessages,
+                ZenModeConfig.sourceToString(config.allowMessagesFrom),
                 config.allowEvents, config.allowReminders);
         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
         if (config.automaticRules.isEmpty()) return;
@@ -271,7 +400,7 @@
                 }
                 config.manualRule = null;  // don't restore the manual rule
                 if (config.automaticRules != null) {
-                    for (ZenModeConfig.ZenRule automaticRule : config.automaticRules.values()) {
+                    for (ZenRule automaticRule : config.automaticRules.values()) {
                         // don't restore transient state from restored automatic rules
                         automaticRule.snoozing = false;
                         automaticRule.condition = null;
@@ -318,36 +447,41 @@
     }
 
     private boolean setConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
-        if (config == null || !config.isValid()) {
-            Log.w(TAG, "Invalid config in setConfig; " + config);
-            return false;
-        }
-        if (config.user != mUser) {
-            // simply store away for background users
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            if (config == null || !config.isValid()) {
+                Log.w(TAG, "Invalid config in setConfig; " + config);
+                return false;
+            }
+            if (config.user != mUser) {
+                // simply store away for background users
+                mConfigs.put(config.user, config);
+                if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
+                return true;
+            }
+            mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
             mConfigs.put(config.user, config);
-            if (DEBUG) Log.d(TAG, "setConfig: store config for user " + config.user);
+            if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
+            ZenLog.traceConfig(reason, mConfig, config);
+            final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
+                    getNotificationPolicy(config));
+            mConfig = config;
+            if (config.equals(mConfig)) {
+                dispatchOnConfigChanged();
+            }
+            if (policyChanged){
+                dispatchOnPolicyChanged();
+            }
+            final String val = Integer.toString(mConfig.hashCode());
+            Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+            if (!evaluateZenMode(reason, setRingerMode)) {
+                applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
+            }
+            mConditions.evaluateConfig(config, true /*processSubscriptions*/);
             return true;
+        } finally {
+            Binder.restoreCallingIdentity(identity);
         }
-        mConditions.evaluateConfig(config, false /*processSubscriptions*/);  // may modify config
-        mConfigs.put(config.user, config);
-        if (DEBUG) Log.d(TAG, "setConfig reason=" + reason, new Throwable());
-        ZenLog.traceConfig(reason, mConfig, config);
-        final boolean policyChanged = !Objects.equals(getNotificationPolicy(mConfig),
-                getNotificationPolicy(config));
-        mConfig = config;
-        if (config.equals(mConfig)) {
-            dispatchOnConfigChanged();
-        }
-        if (policyChanged){
-            dispatchOnPolicyChanged();
-        }
-        final String val = Integer.toString(mConfig.hashCode());
-        Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
-        if (!evaluateZenMode(reason, setRingerMode)) {
-            applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
-        }
-        mConditions.evaluateConfig(config, true /*processSubscriptions*/);
-        return true;
     }
 
     private int getZenModeSetting() {
@@ -505,6 +639,7 @@
                 .getString(R.string.zen_mode_default_weeknights_name);
         rule1.conditionId = ZenModeConfig.toScheduleConditionId(weeknights);
         rule1.zenMode = Global.ZEN_MODE_ALARMS;
+        rule1.component = ScheduleConditionProvider.COMPONENT;
         config.automaticRules.put(config.newRuleId(), rule1);
 
         final ScheduleInfo weekends = new ScheduleInfo();
@@ -518,6 +653,7 @@
                 .getString(R.string.zen_mode_default_weekends_name);
         rule2.conditionId = ZenModeConfig.toScheduleConditionId(weekends);
         rule2.zenMode = Global.ZEN_MODE_ALARMS;
+        rule2.component = ScheduleConditionProvider.COMPONENT;
         config.automaticRules.put(config.newRuleId(), rule2);
     }
 
@@ -532,6 +668,7 @@
         rule.name = mContext.getResources().getString(R.string.zen_mode_default_events_name);
         rule.conditionId = ZenModeConfig.toEventConditionId(events);
         rule.zenMode = Global.ZEN_MODE_ALARMS;
+        rule.component = EventConditionProvider.COMPONENT;
         config.automaticRules.put(config.newRuleId(), rule);
     }
 
@@ -572,6 +709,7 @@
                 rule.conditionId = ZenModeConfig.toScheduleConditionId(schedule);
                 rule.zenMode = v1.sleepNone ? Global.ZEN_MODE_NO_INTERRUPTIONS
                         : Global.ZEN_MODE_IMPORTANT_INTERRUPTIONS;
+                rule.component = ScheduleConditionProvider.COMPONENT;
                 rt.automaticRules.put(rt.newRuleId(), rule);
             } else {
                 Log.i(TAG, "No existing V1 downtime found, generating default schedules");
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index f292c9c..d867616 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -31,6 +31,21 @@
 public final class Installer extends SystemService {
     private static final String TAG = "Installer";
 
+    /* ***************************************************************************
+     * IMPORTANT: These values are passed to native code. Keep them in sync with
+     * frameworks/native/cmds/installd/installd.h
+     * **************************************************************************/
+    /** Application should be visible to everyone */
+    public static final int DEXOPT_PUBLIC       = 1 << 1;
+    /** Application wants to run in VM safe mode */
+    public static final int DEXOPT_SAFEMODE     = 1 << 2;
+    /** Application wants to allow debugging of its code */
+    public static final int DEXOPT_DEBUGGABLE   = 1 << 3;
+    /** The system boot has finished */
+    public static final int DEXOPT_BOOTCOMPLETE = 1 << 4;
+    /** Run the application with the JIT compiler */
+    public static final int DEXOPT_USEJIT       = 1 << 5;
+
     private final InstallerConnection mInstaller;
 
     public Installer(Context context) {
@@ -75,39 +90,24 @@
         return mInstaller.execute(builder.toString());
     }
 
-    public int dexopt(String apkPath, int uid, boolean isPublic,
-            String instructionSet, int dexoptNeeded) {
-        return dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded, true);
-    }
-
-    public int dexopt(String apkPath, int uid, boolean isPublic,
-            String instructionSet, int dexoptNeeded, boolean bootComplete) {
+    public int dexopt(String apkPath, int uid, String instructionSet,
+            int dexoptNeeded, int dexFlags) {
         if (!isValidInstructionSet(instructionSet)) {
             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
             return -1;
         }
 
-        return mInstaller.dexopt(apkPath, uid, isPublic, instructionSet, dexoptNeeded,
-                bootComplete);
+        return mInstaller.dexopt(apkPath, uid, instructionSet, dexoptNeeded, dexFlags);
     }
 
-    public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, int dexoptNeeded, boolean vmSafeMode,
-            boolean debuggable, @Nullable String outputPath) {
-        return dexopt(apkPath, uid, isPublic, pkgName, instructionSet, dexoptNeeded, vmSafeMode,
-                debuggable, outputPath, true);
-    }
-
-    public int dexopt(String apkPath, int uid, boolean isPublic, String pkgName,
-            String instructionSet, int dexoptNeeded, boolean vmSafeMode,
-            boolean debuggable, @Nullable String outputPath, boolean bootComplete) {
+    public int dexopt(String apkPath, int uid, String pkgName, String instructionSet,
+            int dexoptNeeded, @Nullable String outputPath, int dexFlags) {
         if (!isValidInstructionSet(instructionSet)) {
             Slog.e(TAG, "Invalid instruction set: " + instructionSet);
             return -1;
         }
-        return mInstaller.dexopt(apkPath, uid, isPublic, pkgName,
-                instructionSet, dexoptNeeded, vmSafeMode,
-                debuggable, outputPath, bootComplete);
+        return mInstaller.dexopt(apkPath, uid, pkgName, instructionSet, dexoptNeeded,
+                outputPath, dexFlags);
     }
 
     public int idmap(String targetApkPath, String overlayApkPath, int uid) {
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index b692def..6c6871f 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -35,6 +35,11 @@
 
 import dalvik.system.DexFile;
 
+import static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
+import static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
+import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
+import static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
+import static com.android.server.pm.Installer.DEXOPT_USEJIT;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
 
@@ -71,7 +76,8 @@
      * {@link PackageManagerService#mInstallLock}.
      */
     int performDexOpt(PackageParser.Package pkg, String[] instructionSets,
-            boolean forceDex, boolean defer, boolean inclDependencies, boolean bootComplete) {
+            boolean forceDex, boolean defer, boolean inclDependencies,
+            boolean bootComplete, boolean useJit) {
         ArraySet<String> done;
         if (inclDependencies && (pkg.usesLibraries != null || pkg.usesOptionalLibraries != null)) {
             done = new ArraySet<String>();
@@ -86,7 +92,8 @@
                 mDexoptWakeLock.acquire();
             }
             try {
-                return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete, done);
+                return performDexOptLI(pkg, instructionSets, forceDex, defer, bootComplete,
+                        useJit, done);
             } finally {
                 if (useLock) {
                     mDexoptWakeLock.release();
@@ -96,7 +103,8 @@
     }
 
     private int performDexOptLI(PackageParser.Package pkg, String[] targetInstructionSets,
-            boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
+            boolean forceDex, boolean defer, boolean bootComplete, boolean useJit,
+            ArraySet<String> done) {
         final String[] instructionSets = targetInstructionSets != null ?
                 targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
 
@@ -104,11 +112,11 @@
             done.add(pkg.packageName);
             if (pkg.usesLibraries != null) {
                 performDexOptLibsLI(pkg.usesLibraries, instructionSets, forceDex, defer,
-                        bootComplete, done);
+                        bootComplete, useJit, done);
             }
             if (pkg.usesOptionalLibraries != null) {
                 performDexOptLibsLI(pkg.usesOptionalLibraries, instructionSets, forceDex, defer,
-                        bootComplete, done);
+                        bootComplete, useJit, done);
             }
         }
 
@@ -175,11 +183,17 @@
                     Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
                             + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
                             + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
-                            + " oatDir = " + oatDir + " bootComplete=" + bootComplete);
+                            + " oatDir = " + oatDir + " bootComplete=" + bootComplete
+                            + " useJit=" + useJit);
                     final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
+                    final int dexFlags =
+                            (!pkg.isForwardLocked() ? DEXOPT_PUBLIC : 0)
+                            | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
+                            | (debuggable ? DEXOPT_DEBUGGABLE : 0)
+                            | (bootComplete ? DEXOPT_BOOTCOMPLETE : 0)
+                            | (useJit ? DEXOPT_USEJIT : 0);
                     final int ret = mPackageManagerService.mInstaller.dexopt(path, sharedGid,
-                            !pkg.isForwardLocked(), pkg.packageName, dexCodeInstructionSet,
-                            dexoptNeeded, vmSafeMode, debuggable, oatDir, bootComplete);
+                            pkg.packageName, dexCodeInstructionSet, dexoptNeeded, oatDir, dexFlags);
 
                     // Dex2oat might fail due to compiler / verifier errors. We soldier on
                     // regardless, and attempt to interpret the app as a safety net.
@@ -236,12 +250,13 @@
     }
 
     private void performDexOptLibsLI(ArrayList<String> libs, String[] instructionSets,
-            boolean forceDex, boolean defer, boolean bootComplete, ArraySet<String> done) {
+            boolean forceDex, boolean defer, boolean bootComplete, boolean useJit,
+            ArraySet<String> done) {
         for (String libName : libs) {
             PackageParser.Package libPkg = mPackageManagerService.findSharedNonSystemLibrary(
                     libName);
             if (libPkg != null && !done.contains(libName)) {
-                performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, done);
+                performDexOptLI(libPkg, instructionSets, forceDex, defer, bootComplete, useJit, done);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index af0a73e..c729e28 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -75,6 +75,7 @@
 import static com.android.internal.content.NativeLibraryHelper.LIB64_DIR_NAME;
 import static com.android.internal.content.NativeLibraryHelper.LIB_DIR_NAME;
 import static com.android.internal.util.ArrayUtils.appendInt;
+import static com.android.server.pm.Installer.DEXOPT_PUBLIC;
 import static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSet;
 import static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
@@ -2015,7 +2016,8 @@
                             int dexoptNeeded = DexFile.getDexOptNeeded(lib, null, dexCodeInstructionSet, false);
                             if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
                                 alreadyDexOpted.add(lib);
-                                mInstaller.dexopt(lib, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
+                                mInstaller.dexopt(lib, Process.SYSTEM_UID, dexCodeInstructionSet,
+                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Library not found: " + lib);
@@ -2063,7 +2065,8 @@
                         try {
                             int dexoptNeeded = DexFile.getDexOptNeeded(path, null, dexCodeInstructionSet, false);
                             if (dexoptNeeded != DexFile.NO_DEXOPT_NEEDED) {
-                                mInstaller.dexopt(path, Process.SYSTEM_UID, true, dexCodeInstructionSet, dexoptNeeded, false);
+                                mInstaller.dexopt(path, Process.SYSTEM_UID, dexCodeInstructionSet,
+                                        dexoptNeeded, DEXOPT_PUBLIC /*dexFlags*/);
                             }
                         } catch (FileNotFoundException e) {
                             Slog.w(TAG, "Jar not found: " + path);
@@ -6156,41 +6159,6 @@
                     it.remove();
                 }
             }
-            // Give priority to system apps.
-            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
-                PackageParser.Package pkg = it.next();
-                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp()) {
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Adding system app " + sortedPkgs.size() + ": " + pkg.packageName);
-                    }
-                    sortedPkgs.add(pkg);
-                    it.remove();
-                }
-            }
-            // Give priority to updated system apps.
-            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
-                PackageParser.Package pkg = it.next();
-                if (pkg.isUpdatedSystemApp()) {
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Adding updated system app " + sortedPkgs.size() + ": " + pkg.packageName);
-                    }
-                    sortedPkgs.add(pkg);
-                    it.remove();
-                }
-            }
-            // Give priority to apps that listen for boot complete.
-            intent = new Intent(Intent.ACTION_BOOT_COMPLETED);
-            pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM);
-            for (Iterator<PackageParser.Package> it = pkgs.iterator(); it.hasNext();) {
-                PackageParser.Package pkg = it.next();
-                if (pkgNames.contains(pkg.packageName)) {
-                    if (DEBUG_DEXOPT) {
-                        Log.i(TAG, "Adding boot app " + sortedPkgs.size() + ": " + pkg.packageName);
-                    }
-                    sortedPkgs.add(pkg);
-                    it.remove();
-                }
-            }
             // Filter out packages that aren't recently used.
             filterRecentlyUsedApps(pkgs);
             // Add all remaining apps.
@@ -6283,7 +6251,7 @@
         synchronized (mInstallLock) {
             mPackageDexOptimizer.performDexOpt(p, null /* instruction sets */,
                     false /* force dex */, false /* defer */, true /* include dependencies */,
-                    false /* boot complete */);
+                    false /* boot complete */, false /*useJit*/);
         }
     }
 
@@ -6343,7 +6311,7 @@
                 final String[] instructionSets = new String[] { targetInstructionSet };
                 int result = mPackageDexOptimizer.performDexOpt(p, instructionSets,
                         false /* forceDex */, false /* defer */, true /* inclDependencies */,
-                        true /* boot complete */);
+                        true /* boot complete */, false /*useJit*/);
                 return result == PackageDexOptimizer.DEX_OPT_PERFORMED;
             }
         } finally {
@@ -6394,7 +6362,7 @@
 
             final int res = mPackageDexOptimizer.performDexOpt(pkg, instructionSets,
                     true /*forceDex*/, false /* defer */, true /* inclDependencies */,
-                    true /* boot complete */);
+                    true /* boot complete */, false /*useJit*/);
 
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (res != PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -7211,7 +7179,7 @@
 
             int result = mPackageDexOptimizer.performDexOpt(pkg, null /* instruction sets */,
                     forceDex, (scanFlags & SCAN_DEFER_DEX) != 0, false /* inclDependencies */,
-                    (scanFlags & SCAN_BOOTING) == 0);
+                    (scanFlags & SCAN_BOOTING) == 0, false /*useJit*/);
 
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
@@ -7292,7 +7260,7 @@
                         int result = mPackageDexOptimizer.performDexOpt(clientPkg,
                                 null /* instruction sets */, forceDex,
                                 (scanFlags & SCAN_DEFER_DEX) != 0, false,
-                                (scanFlags & SCAN_BOOTING) == 0);
+                                (scanFlags & SCAN_BOOTING) == 0, false /*useJit*/);
                         if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                             throw new PackageManagerException(INSTALL_FAILED_DEXOPT,
                                     "scanPackageLI failed to dexopt clientLibPkgs");
@@ -7916,7 +7884,7 @@
 
                         int result = mPackageDexOptimizer.performDexOpt(ps.pkg,
                                 null /* instruction sets */, forceDexOpt, deferDexOpt, true,
-                                bootComplete);
+                                bootComplete, false /*useJit*/);
 
                         Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                         if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
@@ -12607,8 +12575,7 @@
             int result = mPackageDexOptimizer
                     .performDexOpt(pkg, null /* instruction sets */, false /* forceDex */,
                             false /* defer */, false /* inclDependencies */,
-                            true /* boot complete */);
-
+                            true /*bootComplete*/, false /*useJit*/);
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
             if (result == PackageDexOptimizer.DEX_OPT_FAILED) {
                 res.setError(INSTALL_FAILED_DEXOPT, "Dexopt failed for " + pkg.codePath);
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 1924bab..de106a1 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -16,6 +16,7 @@
 
 package com.android.server.pm;
 
+import android.accounts.Account;
 import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -63,6 +64,7 @@
 import com.android.internal.app.IAppOpsService;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
+import com.android.server.accounts.AccountManagerService;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -129,7 +131,7 @@
 
     private static final int MIN_USER_ID = 10;
 
-    private static final int USER_VERSION = 5;
+    private static final int USER_VERSION = 6;
 
     private static final long EPOCH_PLUS_30_YEARS = 30L * 365 * 24 * 60 * 60 * 1000L; // ms
 
@@ -406,6 +408,24 @@
         }
     }
 
+    @Override
+    public boolean canHaveRestrictedProfile(int userId) {
+        checkManageUsersPermission("canHaveRestrictedProfile");
+        synchronized (mPackagesLock) {
+            final UserInfo userInfo = getUserInfoLocked(userId);
+            if (userInfo == null || !userInfo.canHaveProfile()) {
+                return false;
+            }
+            if (!userInfo.isAdmin()) {
+                return false;
+            }
+        }
+        DevicePolicyManager dpm = (DevicePolicyManager) mContext.getSystemService(
+                Context.DEVICE_POLICY_SERVICE);
+        // restricted profile can be created if there is no DO set and the admin user has no PO
+        return dpm.getDeviceOwner() == null && dpm.getProfileOwnerAsUser(userId) == null;
+    }
+
     /*
      * Should be locked on mUsers before calling this.
      */
@@ -846,6 +866,20 @@
             userVersion = 5;
         }
 
+        if (userVersion < 6) {
+            final boolean splitSystemUser = UserManager.isSplitSystemUser();
+            for (int i = 0; i < mUsers.size(); i++) {
+                UserInfo user = mUsers.valueAt(i);
+                // In non-split mode, only user 0 can have restricted profiles
+                if (!splitSystemUser && user.isRestricted()
+                        && (user.restrictedProfileParentId == UserInfo.NO_PROFILE_GROUP_ID)) {
+                    user.restrictedProfileParentId = UserHandle.USER_SYSTEM;
+                    scheduleWriteUserLocked(user);
+                }
+            }
+            userVersion = 6;
+        }
+
         if (userVersion < USER_VERSION) {
             Slog.w(LOG_TAG, "User version " + mUserVersion + " didn't upgrade as expected to "
                     + USER_VERSION);
@@ -1386,6 +1420,25 @@
     }
 
     /**
+     * @hide
+     */
+    public UserInfo createRestrictedProfile(String name, int parentUserId) {
+        checkManageUsersPermission("setupRestrictedProfile");
+        final UserInfo user = createProfileForUser(name, UserInfo.FLAG_RESTRICTED, parentUserId);
+        if (user == null) {
+            return null;
+        }
+        setUserRestriction(UserManager.DISALLOW_MODIFY_ACCOUNTS, true, user.id);
+        // Change the setting before applying the DISALLOW_SHARE_LOCATION restriction, otherwise
+        // the putIntForUser() will fail.
+        android.provider.Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                android.provider.Settings.Secure.LOCATION_MODE,
+                android.provider.Settings.Secure.LOCATION_MODE_OFF, user.id);
+        setUserRestriction(UserManager.DISALLOW_SHARE_LOCATION, true, user.id);
+        return user;
+    }
+
+    /**
      * Find the current guest user. If the Guest user is partial,
      * then do not include it in the results as it is about to die.
      */
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 04d382d..c265000 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2003,6 +2003,7 @@
             case TYPE_SYSTEM_DIALOG:
             case TYPE_VOLUME_OVERLAY:
             case TYPE_PRIVATE_PRESENTATION:
+            case TYPE_DOCK_DIVIDER:
                 break;
         }
 
@@ -2104,6 +2105,8 @@
         case TYPE_WALLPAPER:
             // wallpaper is at the bottom, though the window manager may move it.
             return 2;
+        case TYPE_DOCK_DIVIDER:
+            return 2;
         case TYPE_PHONE:
             return 3;
         case TYPE_SEARCH_BAR:
@@ -2271,6 +2274,7 @@
             case TYPE_WALLPAPER:
             case TYPE_DREAM:
             case TYPE_KEYGUARD_SCRIM:
+            case TYPE_DOCK_DIVIDER:
                 return false;
             default:
                 // Hide only windows below the keyguard host window.
@@ -4428,6 +4432,7 @@
         if (attrs.type == TYPE_STATUS_BAR) {
             if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
                 mForceStatusBarFromKeyguard = true;
+                mShowingLockscreen = true;
             }
             if ((attrs.privateFlags & PRIVATE_FLAG_FORCE_STATUS_BAR_VISIBLE_TRANSPARENT) != 0) {
                 mForceStatusBarTransparent = true;
@@ -4448,9 +4453,6 @@
                     mForceStatusBar = true;
                 }
             }
-            if ((attrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0) {
-                mShowingLockscreen = true;
-            }
             if (attrs.type == TYPE_DREAM) {
                 // If the lockscreen was showing when the dream started then wait
                 // for the dream to draw before hiding the lockscreen.
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 5d01931..25d646d 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -28,5 +28,5 @@
     void showScreenPinningRequest();
     void showAssistDisclosure();
     void startAssist(Bundle args);
-    void onCameraLaunchGestureDetected();
+    void onCameraLaunchGestureDetected(int source);
 }
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 11a1639..19b03d5 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -178,10 +178,10 @@
         }
 
         @Override
-        public void onCameraLaunchGestureDetected() {
+        public void onCameraLaunchGestureDetected(int source) {
             if (mBar != null) {
                 try {
-                    mBar.onCameraLaunchGestureDetected();
+                    mBar.onCameraLaunchGestureDetected(source);
                 } catch (RemoteException e) {
                 }
             }
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 192b168..cc51d20 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1003,19 +1003,36 @@
         return prepareThumbnailAnimation(a, appWidth, appHeight, transit);
     }
 
-    private Animation createRelaunchAnimation(int appWidth, int appHeight) {
+    private Animation createRelaunchAnimation(int appWidth, int appHeight,
+            Rect containingFrame) {
         getDefaultNextAppTransitionStartRect(mTmpFromClipRect);
         final int left = mTmpFromClipRect.left;
         final int top = mTmpFromClipRect.top;
         mTmpFromClipRect.offset(-left, -top);
         mTmpToClipRect.set(0, 0, appWidth, appHeight);
         AnimationSet set = new AnimationSet(true);
-        ClipRectAnimation clip = new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect);
-        TranslateAnimation translate = new TranslateAnimation(left, 0, top, 0);
-        clip.setInterpolator(mDecelerateInterpolator);
-        set.addAnimation(clip);
+        float fromWidth = mTmpFromClipRect.width();
+        float toWidth = mTmpToClipRect.width();
+        float fromHeight = mTmpFromClipRect.height();
+        float toHeight = mTmpToClipRect.height();
+        if (fromWidth <= toWidth && fromHeight <= toHeight) {
+            // The final window is larger in both dimensions than current window (e.g. we are
+            // maximizing), so we can simply unclip the new window and there will be no disappearing
+            // frame.
+            set.addAnimation(new ClipRectAnimation(mTmpFromClipRect, mTmpToClipRect));
+        } else {
+            // The disappearing window has one larger dimension. We need to apply scaling, so the
+            // first frame of the entry animation matches the old window.
+            set.addAnimation(new ScaleAnimation(fromWidth / toWidth, 1, fromHeight / toHeight, 1));
+        }
+
+        // We might not be going exactly full screen, but instead be aligned under the status bar.
+        // We need to take this into account when creating the translate animation.
+        TranslateAnimation translate = new TranslateAnimation(left - containingFrame.left,
+                0, top - containingFrame.top, 0);
         set.addAnimation(translate);
         set.setDuration(DEFAULT_APP_TRANSITION_DURATION);
+        set.setZAdjustment(Animation.ZORDER_TOP);
         return set;
     }
 
@@ -1056,7 +1073,12 @@
                     + " anim=" + a + " transit=" + appTransitionToString(transit)
                     + " isEntrance=" + enter + " Callers=" + Debug.getCallers(3));
         } else if (transit == TRANSIT_ACTIVITY_RELAUNCH) {
-            a = createRelaunchAnimation(appWidth, appHeight);
+            a = createRelaunchAnimation(appWidth, appHeight, containingFrame);
+            if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
+                    "applyAnimation:"
+                    + " anim=" + a + " nextAppTransition=" + mNextAppTransition
+                    + " transit=" + appTransitionToString(transit)
+                    + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
             a = loadAnimationRes(mNextAppTransitionPackage, enter ?
                     mNextAppTransitionEnter : mNextAppTransitionExit);
@@ -1077,6 +1099,7 @@
             if (DEBUG_APP_TRANSITIONS || DEBUG_ANIM) Slog.v(TAG,
                     "applyAnimation:"
                             + " anim=" + a + " nextAppTransition=ANIM_CLIP_REVEAL"
+                            + " transit=" + appTransitionToString(transit)
                             + " Callers=" + Debug.getCallers(3));
         } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
             a = createScaleUpAnimationLocked(transit, enter, appWidth, appHeight);
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index ff216c5..5a1ed58 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -74,10 +74,6 @@
     // case do not clear allDrawn until the animation completes.
     boolean deferClearAllDrawn;
 
-    // Is this token going to be hidden in a little while?  If so, it
-    // won't be taken into account for setting the screen orientation.
-    boolean willBeHidden;
-
     // Is this window's surface needed?  This is almost like hidden, except
     // it will sometimes be true a little earlier: when the token has
     // been shown, but is still waiting for its app transition to execute
@@ -321,7 +317,6 @@
                 pw.print(" requestedOrientation="); pw.println(requestedOrientation);
         pw.print(prefix); pw.print("hiddenRequested="); pw.print(hiddenRequested);
                 pw.print(" clientHidden="); pw.print(clientHidden);
-                pw.print(" willBeHidden="); pw.print(willBeHidden);
                 pw.print(" reportedDrawn="); pw.print(reportedDrawn);
                 pw.print(" reportedVisible="); pw.println(reportedVisible);
         if (paused) {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index cb0dba8..745874c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -16,11 +16,13 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.app.ActivityManager.HOME_STACK_ID;
 
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 import static com.android.server.wm.WindowManagerService.TAG;
 import static com.android.server.wm.WindowState.RESIZE_HANDLE_WIDTH_IN_DP;
+import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 
 import android.graphics.Rect;
 import android.graphics.Region;
@@ -111,6 +113,8 @@
     /** Remove this display when animation on it has completed. */
     boolean mDeferredRemoval;
 
+    final DockedStackDividerController mDividerControllerLocked;
+
     /**
      * @param display May not be null.
      * @param service You know.
@@ -122,6 +126,8 @@
         display.getMetrics(mDisplayMetrics);
         isDefaultDisplay = mDisplayId == Display.DEFAULT_DISPLAY;
         mService = service;
+        initializeDisplayBaseInfo();
+        mDividerControllerLocked = new DockedStackDividerController(service.mContext, this);
     }
 
     int getDisplayId() {
@@ -187,6 +193,21 @@
         }
     }
 
+    void initializeDisplayBaseInfo() {
+        synchronized(mDisplaySizeLock) {
+            // Bootstrap the default logical display from the display manager.
+            final DisplayInfo newDisplayInfo =
+                    mService.mDisplayManagerInternal.getDisplayInfo(mDisplayId);
+            if (newDisplayInfo != null) {
+                mDisplayInfo.copyFrom(newDisplayInfo);
+            }
+            mBaseDisplayWidth = mInitialDisplayWidth = mDisplayInfo.logicalWidth;
+            mBaseDisplayHeight = mInitialDisplayHeight = mDisplayInfo.logicalHeight;
+            mBaseDisplayDensity = mInitialDisplayDensity = mDisplayInfo.logicalDensityDpi;
+            mBaseDisplayRect.set(0, 0, mBaseDisplayWidth, mBaseDisplayHeight);
+        }
+    }
+
     void getLogicalDisplayRect(Rect out) {
         // Uses same calculation as in LogicalDisplay#configureDisplayInTransactionLocked.
         final int orientation = mDisplayInfo.rotation;
@@ -242,7 +263,7 @@
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final Task task = tasks.get(taskNdx);
                 task.getBounds(mTmpRect);
-                if (task.inFreeformWorkspace() && mTmpRect.contains(x, y)) {
+                if (mTmpRect.contains(x, y)) {
                     return task.mTaskId;
                 }
             }
@@ -251,10 +272,10 @@
     }
 
     /**
-     * Find the id of the task whose outside touch area (for resizing) (x, y)
-     * falls within. Returns -1 if the touch doesn't fall into a resizing area.
+     * Find the window whose outside touch area (for resizing) (x, y) falls within.
+     * Returns null if the touch doesn't fall into a resizing area.
      */
-    int taskIdForControlPoint(int x, int y) {
+    WindowState findWindowForControlPoint(int x, int y) {
         final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, mDisplayMetrics);
         for (int stackNdx = mStacks.size() - 1; stackNdx >= 0; --stackNdx) {
             TaskStack stack = mStacks.get(stackNdx);
@@ -265,22 +286,31 @@
             for (int taskNdx = tasks.size() - 1; taskNdx >= 0; --taskNdx) {
                 final Task task = tasks.get(taskNdx);
                 if (task.isFullscreen()) {
-                    return -1;
+                    return null;
                 }
-                task.getBounds(mTmpRect);
-                mTmpRect.inset(-delta, -delta);
-                if (mTmpRect.contains(x, y)) {
-                    mTmpRect.inset(delta, delta);
-                    if (!mTmpRect.contains(x, y)) {
-                        return task.mTaskId;
+
+                // We need to use the visible frame on the window for any touch-related
+                // tests. Can't use the task's bounds because the original task bounds
+                // might be adjusted to fit the content frame. (One example is when the
+                // task is put to top-left quadrant, the actual visible frame would not
+                // start at (0,0) after it's adjusted for the status bar.)
+                WindowState win = task.getTopAppMainWindow();
+                if (win != null) {
+                    win.getVisibleBounds(mTmpRect, !BOUNDS_FOR_TOUCH);
+                    mTmpRect.inset(-delta, -delta);
+                    if (mTmpRect.contains(x, y)) {
+                        mTmpRect.inset(delta, delta);
+                        if (!mTmpRect.contains(x, y)) {
+                            return win;
+                        }
+                        // User touched inside the task. No need to look further,
+                        // focus transfer will be handled in ACTION_UP.
+                        return null;
                     }
-                    // User touched inside the task. No need to look further,
-                    // focus transfer will be handled in ACTION_UP.
-                    return -1;
                 }
             }
         }
-        return -1;
+        return null;
     }
 
     void setTouchExcludeRegion(Task focusedTask) {
@@ -552,4 +582,14 @@
     public String toString() {
         return "Display " + mDisplayId + " info=" + mDisplayInfo + " stacks=" + mStacks;
     }
+
+    TaskStack getDockedStackLocked() {
+        for (int i = mStacks.size() - 1; i >= 0; i--) {
+            TaskStack stack = mStacks.get(i);
+            if (stack.mStackId == DOCKED_STACK_ID && stack.isVisibleLocked()) {
+                return stack;
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
new file mode 100644
index 0000000..8c5d319
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -0,0 +1,199 @@
+/*
+ * 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.wm;
+
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;
+import static android.view.WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
+import static android.view.WindowManager.LayoutParams.FLAG_TOUCHABLE_WHEN_WAKING;
+import static android.view.WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.TaskStack.DOCKED_BOTTOM;
+import static com.android.server.wm.TaskStack.DOCKED_INVALID;
+import static com.android.server.wm.TaskStack.DOCKED_LEFT;
+import static com.android.server.wm.TaskStack.DOCKED_RIGHT;
+import static com.android.server.wm.TaskStack.DOCKED_TOP;
+
+import android.content.Context;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.os.RemoteException;
+import android.util.Slog;
+import android.view.LayoutInflater;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
+
+/**
+ * Controls showing and hiding of a docked stack divider on the display.
+ */
+public class DockedStackDividerController implements View.OnTouchListener {
+    private static final String TAG = "DockedStackDivider";
+    private final Context mContext;
+    private final int mDividerWidth;
+    private final DisplayContent mDisplayContent;
+    private View mView;
+    private Rect mTmpRect = new Rect();
+    private Rect mLastResizeRect = new Rect();
+    private int mStartX;
+    private int mStartY;
+    private TaskStack mTaskStack;
+    private Rect mOriginalRect = new Rect();
+    private int mDockSide;
+
+
+    DockedStackDividerController(Context context, DisplayContent displayContent) {
+        mContext = context;
+        mDisplayContent = displayContent;
+        mDividerWidth = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.docked_stack_divider_thickness);
+    }
+
+    private void addDivider() {
+        View view = LayoutInflater.from(mContext).inflate(
+                com.android.internal.R.layout.docked_stack_divider, null);
+        view.setOnTouchListener(this);
+        WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+        WindowManager.LayoutParams params = new WindowManager.LayoutParams(
+                mDividerWidth, MATCH_PARENT, TYPE_DOCK_DIVIDER,
+                FLAG_TOUCHABLE_WHEN_WAKING | FLAG_NOT_FOCUSABLE | FLAG_NOT_TOUCH_MODAL
+                        | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH,
+                PixelFormat.OPAQUE);
+        params.setTitle(TAG);
+        manager.addView(view, params, mDisplayContent.getDisplay(), null);
+        mView = view;
+    }
+
+    private void removeDivider() {
+        mView.setOnTouchListener(null);
+        WindowManagerGlobal manager = WindowManagerGlobal.getInstance();
+        manager.removeView(mView, true /* immediate */);
+        mView = null;
+    }
+
+    boolean hasDivider() {
+        return mView != null;
+    }
+
+    void update() {
+        TaskStack stack = mDisplayContent.getDockedStackLocked();
+        if (stack != null && mView == null) {
+            addDivider();
+        } else if (stack == null && mView != null) {
+            removeDivider();
+        }
+    }
+
+    int getWidth() {
+        return mDividerWidth;
+    }
+
+    void positionDockedStackedDivider(Rect frame) {
+        TaskStack stack = mDisplayContent.getDockedStackLocked();
+        if (stack == null) {
+            // Unfortunately we might end up with still having a divider, even though the underlying
+            // stack was already removed. This is because we are on AM thread and the removal of the
+            // divider was deferred to WM thread and hasn't happened yet.
+            return;
+        }
+        final @TaskStack.DockSide int side = stack.getDockSide();
+        stack.getBounds(mTmpRect);
+        switch (side) {
+            case DOCKED_LEFT:
+                frame.set(mTmpRect.right, frame.top, mTmpRect.right + frame.width(), frame.bottom);
+                break;
+            case DOCKED_TOP:
+                frame.set(frame.left, mTmpRect.bottom, mTmpRect.right,
+                        mTmpRect.bottom + frame.height());
+                break;
+            case DOCKED_RIGHT:
+                frame.set(mTmpRect.left - frame.width(), frame.top, mTmpRect.left, frame.bottom);
+                break;
+            case DOCKED_BOTTOM:
+                frame.set(frame.left, mTmpRect.top - frame.height(), frame.right, mTmpRect.top);
+                break;
+        }
+    }
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+        final int action = event.getAction() & MotionEvent.ACTION_MASK;
+        switch (action) {
+            case MotionEvent.ACTION_DOWN:
+                // We use raw values, because getX/Y() would give us results relative to the
+                // dock divider bounds.
+                mStartX = (int) event.getRawX();
+                mStartY = (int) event.getRawY();
+                synchronized (mDisplayContent.mService.mWindowMap) {
+                    mTaskStack = mDisplayContent.getDockedStackLocked();
+                    mTaskStack.getBounds(mOriginalRect);
+                    mDockSide = mTaskStack.getDockSide();
+                }
+                break;
+            case MotionEvent.ACTION_MOVE:
+                if (mTaskStack != null) {
+                    resizeStack(event);
+                }
+                break;
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mTaskStack = null;
+                mDockSide = TaskStack.DOCKED_INVALID;
+                break;
+        }
+        return true;
+    }
+
+    private void resizeStack(MotionEvent event) {
+        mTmpRect.set(mOriginalRect);
+        final int deltaX = (int) event.getRawX() - mStartX;
+        final int deltaY = (int) event.getRawY() - mStartY;
+        switch (mDockSide) {
+            case DOCKED_LEFT:
+                mTmpRect.right += deltaX;
+                break;
+            case DOCKED_TOP:
+                mTmpRect.bottom += deltaY;
+                break;
+            case DOCKED_RIGHT:
+                mTmpRect.left += deltaX;
+                break;
+            case DOCKED_BOTTOM:
+                mTmpRect.top += deltaY;
+                break;
+        }
+        if (mTmpRect.equals(mLastResizeRect)) {
+            return;
+        }
+        mLastResizeRect.set(mTmpRect);
+        try {
+            mDisplayContent.mService.mActivityManager.resizeStack(DOCKED_STACK_ID, mTmpRect);
+        } catch (RemoteException e) {
+        }
+    }
+
+    boolean isResizing() {
+        return mTaskStack != null;
+    }
+
+    int getWidthAdjustment() {
+        return getWidth() / 2;
+    }
+}
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 4244205..6c391ad 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static com.android.server.wm.WindowState.BOUNDS_FOR_TOUCH;
 import android.app.ActivityManagerNative;
 import android.graphics.Rect;
@@ -170,7 +171,7 @@
 
     private void addInputWindowHandleLw(final InputWindowHandle inputWindowHandle,
             final WindowState child, int flags, final int type, final boolean isVisible,
-            final boolean hasFocus, final boolean hasWallpaper) {
+            final boolean hasFocus, final boolean hasWallpaper, DisplayContent displayContent) {
         // Add a window to our list of input windows.
         inputWindowHandle.name = child.toString();
         final boolean modal = (flags & (WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
@@ -202,6 +203,20 @@
         inputWindowHandle.frameTop = frame.top;
         inputWindowHandle.frameRight = frame.right;
         inputWindowHandle.frameBottom = frame.bottom;
+        if (child.mAttrs.type == TYPE_DOCK_DIVIDER) {
+            // We need to determine if the divider is horizontal or vertical and adjust its handle
+            // frame accordingly.
+            int adjustment = displayContent.mDividerControllerLocked.getWidthAdjustment();
+            if (inputWindowHandle.frameRight - inputWindowHandle.frameLeft >
+                    inputWindowHandle.frameTop - inputWindowHandle.frameBottom) {
+                // Horizontal divider.
+                inputWindowHandle.frameTop -= adjustment;
+                inputWindowHandle.frameBottom += adjustment;
+            } else {
+                inputWindowHandle.frameLeft -= adjustment;
+                inputWindowHandle.frameRight += adjustment;
+            }
+        }
 
         if (child.mGlobalScale != 1) {
             // If we are scaling the window, input coordinates need
@@ -277,7 +292,8 @@
         final int numDisplays = mService.mDisplayContents.size();
         final WallpaperController wallpaperController = mService.mWallpaperControllerLocked;
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
-            WindowList windows = mService.mDisplayContents.valueAt(displayNdx).getWindowList();
+            final DisplayContent displayContent = mService.mDisplayContents.valueAt(displayNdx);
+            final WindowList windows = displayContent.getWindowList();
             for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                 final WindowState child = windows.get(winNdx);
                 final InputChannel inputChannel = child.mInputChannel;
@@ -315,7 +331,7 @@
                 }
 
                 addInputWindowHandleLw(inputWindowHandle, child, flags, type, isVisible, hasFocus,
-                        hasWallpaper);
+                        hasWallpaper, displayContent);
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4541dd6..1f986dd 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -16,9 +16,12 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.DOCKED_STACK_ID;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM_SCREEN_ROTATION;
 import static com.android.server.wm.WindowManagerService.TAG;
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerService.H.RESIZE_TASK;
 import static android.app.ActivityManager.FREEFORM_WORKSPACE_STACK_ID;
 
 import android.content.res.Configuration;
@@ -244,8 +247,32 @@
         return true;
     }
 
+    /** Return true if the current bound can get outputted to the rest of the system as-is. */
+    private boolean useCurrentBounds() {
+        final DisplayContent displayContent = mStack.getDisplayContent();
+        if (mFullscreen
+                || mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID
+                || mStack.mStackId == DOCKED_STACK_ID
+                || displayContent == null
+                || displayContent.getDockedStackLocked() != null) {
+            return true;
+        }
+        return false;
+    }
+
+    /** Bounds of the task with other system factors taken into consideration. */
     void getBounds(Rect out) {
-        out.set(mBounds);
+        if (useCurrentBounds()) {
+            // No need to adjust the output bounds if fullscreen or the docked stack is visible
+            // since it is already what we want to represent to the rest of the system.
+            out.set(mBounds);
+            return;
+        }
+
+        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+        // system.
+        mStack.getDisplayContent().getLogicalDisplayRect(out);
     }
 
     void setDragResizing(boolean dragResizing) {
@@ -273,7 +300,13 @@
         // this happens, so update the task bounds so it stays in the same place.
         mTmpRect2.set(mBounds);
         displayContent.rotateBounds(mRotation, newRotation, mTmpRect2);
-        setBounds(mTmpRect2, mOverrideConfig);
+        if (setBounds(mTmpRect2, mOverrideConfig) != BOUNDS_CHANGE_NONE) {
+            // Post message to inform activity manager of the bounds change simulating
+            // a one-way call. We do this to prevent a deadlock between window manager
+            // lock and activity manager lock been held.
+            mService.mH.sendMessage(mService.mH.obtainMessage(
+                            RESIZE_TASK, mTaskId, RESIZE_MODE_SYSTEM_SCREEN_ROTATION, mBounds));
+        }
     }
 
     /** Updates the dim layer bounds, recreating it if needed. */
@@ -432,9 +465,20 @@
         return mStack != null && mStack.mStackId == FREEFORM_WORKSPACE_STACK_ID;
     }
 
+    WindowState getTopAppMainWindow() {
+        final int tokensCount = mAppTokens.size();
+        return tokensCount > 0 ? mAppTokens.get(tokensCount - 1).findMainWindow() : null;
+    }
+
     @Override
     public boolean isFullscreen() {
-        return mFullscreen;
+        if (useCurrentBounds()) {
+            return mFullscreen;
+        }
+        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+        // system.
+        return true;
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index a94be83..df2e5e8 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityManager.RESIZE_MODE_FORCED;
 import static android.app.ActivityManager.RESIZE_MODE_USER;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static com.android.server.wm.WindowManagerService.DEBUG_TASK_POSITIONING;
 import static com.android.server.wm.WindowManagerService.SHOW_TRANSACTIONS;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
@@ -33,14 +34,16 @@
 import android.os.Looper;
 import android.os.Process;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.util.DisplayMetrics;
 import android.util.Slog;
+import android.view.Choreographer;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.InputChannel;
 import android.view.InputDevice;
 import android.view.InputEvent;
-import android.view.InputEventReceiver;
+import android.view.BatchedInputEventReceiver;
 import android.view.MotionEvent;
 import android.view.SurfaceControl;
 import android.view.WindowManager;
@@ -96,15 +99,17 @@
     private float mStartDragY;
     @CtrlType
     private int mCtrlType = CTRL_NONE;
+    private boolean mDragEnded = false;
 
     InputChannel mServerChannel;
     InputChannel mClientChannel;
     InputApplicationHandle mDragApplicationHandle;
     InputWindowHandle mDragWindowHandle;
 
-    private final class WindowPositionerEventReceiver extends InputEventReceiver {
-        public WindowPositionerEventReceiver(InputChannel inputChannel, Looper looper) {
-            super(inputChannel, looper);
+    private final class WindowPositionerEventReceiver extends BatchedInputEventReceiver {
+        public WindowPositionerEventReceiver(
+                InputChannel inputChannel, Looper looper, Choreographer choreographer) {
+            super(inputChannel, looper, choreographer);
         }
 
         @Override
@@ -117,7 +122,14 @@
             boolean handled = false;
 
             try {
-                boolean endDrag = false;
+                if (mDragEnded) {
+                    // The drag has ended but the clean-up message has not been processed by
+                    // window manager. Drop events that occur after this until window manager
+                    // has a chance to clean-up the input handle.
+                    handled = true;
+                    return;
+                }
+
                 final float newX = motionEvent.getRawX();
                 final float newY = motionEvent.getRawY();
 
@@ -133,30 +145,32 @@
                             Slog.w(TAG, "ACTION_MOVE @ {" + newX + ", " + newY + "}");
                         }
                         synchronized (mService.mWindowMap) {
-                            endDrag = notifyMoveLocked(newX, newY);
+                            mDragEnded = notifyMoveLocked(newX, newY);
                         }
+                        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.TaskPositioner.resizeTask");
                         try {
                             mService.mActivityManager.resizeTask(
                                     mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
                         } catch(RemoteException e) {}
+                        Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
                     } break;
 
                     case MotionEvent.ACTION_UP: {
                         if (DEBUG_TASK_POSITIONING) {
                             Slog.w(TAG, "ACTION_UP @ {" + newX + ", " + newY + "}");
                         }
-                        endDrag = true;
+                        mDragEnded = true;
                     } break;
 
                     case MotionEvent.ACTION_CANCEL: {
                         if (DEBUG_TASK_POSITIONING) {
                             Slog.w(TAG, "ACTION_CANCEL @ {" + newX + ", " + newY + "}");
                         }
-                        endDrag = true;
+                        mDragEnded = true;
                     } break;
                 }
 
-                if (endDrag) {
+                if (mDragEnded) {
                     synchronized (mService.mWindowMap) {
                         endDragLocked();
                     }
@@ -214,8 +228,8 @@
         mClientChannel = channels[1];
         mService.mInputManager.registerInputChannel(mServerChannel, null);
 
-        mInputEventReceiver = new WindowPositionerEventReceiver(mClientChannel,
-                mService.mH.getLooper());
+        mInputEventReceiver = new WindowPositionerEventReceiver(
+                mClientChannel, mService.mH.getLooper(), mService.mChoreographer);
 
         mDragApplicationHandle = new InputApplicationHandle(null);
         mDragApplicationHandle.name = TAG;
@@ -262,6 +276,8 @@
         mSideMargin = mService.dipToPixel(SIDE_MARGIN_DIP, mDisplayMetrics);
         mMinVisibleWidth = mService.dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, mDisplayMetrics);
         mMinVisibleHeight = mService.dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, mDisplayMetrics);
+
+        mDragEnded = false;
     }
 
     void unregister() {
@@ -292,6 +308,7 @@
             mDimLayer = null;
         }
         mCurrentDimSide = CTRL_NONE;
+        mDragEnded = true;
 
         // Resume rotations after a drag.
         if (WindowManagerService.DEBUG_ORIENTATION) {
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1362555..10ea4e2 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -18,6 +18,7 @@
 
 import static android.app.ActivityManager.*;
 import static com.android.server.wm.WindowManagerService.DEBUG_TASK_MOVEMENT;
+import static com.android.server.wm.WindowManagerService.H.RESIZE_STACK;
 import static com.android.server.wm.WindowManagerService.TAG;
 
 import android.annotation.IntDef;
@@ -86,6 +87,7 @@
     static final int DOCKED_TOP = 2;
     static final int DOCKED_RIGHT = 3;
     static final int DOCKED_BOTTOM = 4;
+
     @IntDef({
             DOCKED_INVALID,
             DOCKED_LEFT,
@@ -180,12 +182,45 @@
         return true;
     }
 
-    void getBounds(Rect out) {
+    /** Bounds of the stack without adjusting for other factors in the system like visibility
+     * of docked stack.
+     * Most callers should be using {@link #getBounds} as it take into consideration other system
+     * factors. */
+    void getRawBounds(Rect out) {
         out.set(mBounds);
     }
 
+    /** Return true if the current bound can get outputted to the rest of the system as-is. */
+    private boolean useCurrentBounds() {
+        if (mFullscreen
+                || mStackId == DOCKED_STACK_ID
+                || mDisplayContent == null
+                || mDisplayContent.getDockedStackLocked() != null) {
+            return true;
+        }
+        return false;
+    }
+
+    /** Bounds of the stack with other system factors taken into consideration. */
+    void getBounds(Rect out) {
+        if (useCurrentBounds()) {
+            // No need to adjust the output bounds if fullscreen or the docked stack is visible
+            // since it is already what we want to represent to the rest of the system.
+            out.set(mBounds);
+            return;
+        }
+
+        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+        // system.
+        mDisplayContent.getLogicalDisplayRect(out);
+    }
+
     void updateDisplayInfo(Rect bounds) {
         if (mDisplayContent != null) {
+            for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+                mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+            }
             if (bounds != null) {
                 setBounds(bounds);
             } else if (mFullscreen) {
@@ -194,10 +229,13 @@
                 TmpRect2.set(mBounds);
                 mDisplayContent.rotateBounds(
                         mRotation, mDisplayContent.getDisplayInfo().rotation, TmpRect2);
-                setBounds(TmpRect2);
-            }
-            for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                mTasks.get(taskNdx).updateDisplayInfo(mDisplayContent);
+                if (setBounds(TmpRect2)) {
+                    // Post message to inform activity manager of the bounds change simulating
+                    // a one-way call. We do this to prevent a deadlock between window manager
+                    // lock and activity manager lock been held.
+                    mService.mH.sendMessage(
+                            mService.mH.obtainMessage(RESIZE_STACK, mStackId, -1, mBounds));
+                }
             }
         }
     }
@@ -352,7 +390,8 @@
             // the docked stack occupies a dedicated region on screen.
             bounds = new Rect();
             displayContent.getLogicalDisplayRect(mTmpRect);
-            getInitialDockedStackBounds(mTmpRect, bounds, mStackId);
+            getInitialDockedStackBounds(mTmpRect, bounds, mStackId,
+                    mDisplayContent.mDividerControllerLocked.getWidthAdjustment());
         }
 
         updateDisplayInfo(bounds);
@@ -371,27 +410,29 @@
      * @param displayRect The bounds of the display the docked stack is on.
      * @param outBounds Output bounds that should be used for the stack.
      * @param stackId Id of stack we are calculating the bounds for.
+     * @param adjustment
      */
-    private static void getInitialDockedStackBounds(
-            Rect displayRect, Rect outBounds, int stackId) {
+    private static void getInitialDockedStackBounds(Rect displayRect, Rect outBounds, int stackId,
+            int adjustment) {
         // Docked stack start off occupying half the screen space.
+        final boolean dockedStack = stackId == DOCKED_STACK_ID;
         final boolean splitHorizontally = displayRect.width() > displayRect.height();
         final boolean topOrLeftCreateMode =
                 WindowManagerService.sDockedStackCreateMode == DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-        final boolean placeTopOrLeft = (stackId == DOCKED_STACK_ID && topOrLeftCreateMode)
-                || (stackId != DOCKED_STACK_ID && !topOrLeftCreateMode);
+        final boolean placeTopOrLeft = (dockedStack && topOrLeftCreateMode)
+                || (!dockedStack && !topOrLeftCreateMode);
         outBounds.set(displayRect);
         if (placeTopOrLeft) {
             if (splitHorizontally) {
-                outBounds.right = displayRect.centerX();
+                outBounds.right = displayRect.centerX() - adjustment;
             } else {
-                outBounds.bottom = displayRect.centerY();
+                outBounds.bottom = displayRect.centerY() - adjustment;
             }
         } else {
             if (splitHorizontally) {
-                outBounds.left = displayRect.centerX();
+                outBounds.left = displayRect.centerX() + adjustment;
             } else {
-                outBounds.top = displayRect.centerY();
+                outBounds.top = displayRect.centerY() + adjustment;
             }
         }
     }
@@ -404,7 +445,8 @@
     private void resizeNonDockedStacks(boolean fullscreen) {
         mDisplayContent.getLogicalDisplayRect(mTmpRect);
         if (!fullscreen) {
-            getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID);
+            getInitialDockedStackBounds(mTmpRect, mTmpRect, FULLSCREEN_WORKSPACE_STACK_ID,
+                    mDisplayContent.mDividerControllerLocked.getWidth());
         }
 
         final int count = mService.mStackIdToStack.size();
@@ -434,8 +476,7 @@
                 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
                     // We are in the middle of changing the state of displays/stacks/tasks. We need
                     // to finish that, before we let layout interfere with it.
-                    mService.removeWindowInnerLocked(appWindows.get(winNdx),
-                            false /* performLayout */);
+                    mService.removeWindowLocked(appWindows.get(winNdx));
                     doAnotherLayoutPass = true;
                 }
             }
@@ -516,9 +557,23 @@
         }
     }
 
+    /** Fullscreen status of the stack without adjusting for other factors in the system like
+     * visibility of docked stack.
+     * Most callers should be using {@link #isFullscreen} as it take into consideration other
+     * system factors. */
+    boolean getRawFullscreen() {
+        return mFullscreen;
+    }
+
     @Override
     public boolean isFullscreen() {
-        return mFullscreen;
+        if (useCurrentBounds()) {
+            return mFullscreen;
+        }
+        // The bounds has been adjusted to accommodate for a docked stack, but the docked stack
+        // is not currently visible. Go ahead a represent it as fullscreen to the rest of the
+        // system.
+        return true;
     }
 
     @Override
@@ -546,14 +601,14 @@
         final int orientation = mService.mCurConfiguration.orientation;
         if (orientation == Configuration.ORIENTATION_PORTRAIT) {
             // Portrait mode, docked either at the top or the bottom.
-            if (mTmpRect.top - mBounds.top < mTmpRect.bottom - mBounds.bottom) {
+            if (mBounds.top - mTmpRect.top < mTmpRect.bottom - mBounds.bottom) {
                 return DOCKED_TOP;
             } else {
                 return DOCKED_BOTTOM;
             }
         } else if (orientation == Configuration.ORIENTATION_LANDSCAPE) {
             // Landscape mode, docked either on the left or on the right.
-            if (mTmpRect.left - mBounds.left < mTmpRect.right - mBounds.right) {
+            if (mBounds.left - mTmpRect.left < mTmpRect.right - mBounds.right) {
                 return DOCKED_LEFT;
             } else {
                 return DOCKED_RIGHT;
@@ -562,4 +617,16 @@
             return DOCKED_INVALID;
         }
     }
+
+    boolean isVisibleLocked() {
+        for (int i = mTasks.size() - 1; i >= 0; i--) {
+            Task task = mTasks.get(i);
+            for (int j = task.mAppTokens.size() - 1; j >= 0; j--) {
+                if (!task.mAppTokens.get(j).hidden) {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 29598ab..74572cf 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,12 +17,14 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.DOCKED_STACK_ID;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
 import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
 import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
 import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
@@ -33,6 +35,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
 import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
@@ -219,6 +222,7 @@
     static final boolean HIDE_STACK_CRAWLS = true;
     static final int LAYOUT_REPEAT_THRESHOLD = 4;
 
+
     static final boolean PROFILE_ORIENTATION = false;
     static final boolean localLOGV = DEBUG;
 
@@ -921,6 +925,7 @@
         mAllowTheaterModeWakeFromLayout = context.getResources().getBoolean(
                 com.android.internal.R.bool.config_allowTheaterModeWakeFromWindowLayout);
 
+
         LocalServices.addService(WindowManagerInternal.class, new LocalService());
         initPolicy();
 
@@ -1854,6 +1859,11 @@
                             + attrs.token + ".  Aborting.");
                     return WindowManagerGlobal.ADD_BAD_APP_TOKEN;
                 }
+            } else if (type == TYPE_DOCK_DIVIDER) {
+                if (displayContent.mDividerControllerLocked.hasDivider()) {
+                    Slog.w(TAG, "Attempted to add docked stack divider twice. Aborting.");
+                    return WindowManagerGlobal.ADD_MULTIPLE_SINGLETON;
+                }
             } else if (token.appWindowToken != null) {
                 Slog.w(TAG, "Non-null appWindowToken for system window of type=" + type);
                 // It is not valid to use an app token with other system types; we will
@@ -1886,13 +1896,13 @@
                 return res;
             }
 
-            if (outInputChannel != null && (attrs.inputFeatures
-                    & WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL) == 0) {
+            final boolean openInputChannels = (outInputChannel != null
+                    && (attrs.inputFeatures & INPUT_FEATURE_NO_INPUT_CHANNEL) == 0);
+            if  (openInputChannels) {
                 String name = win.makeInputChannelName();
                 InputChannel[] inputChannels = InputChannel.openInputChannelPair(name);
                 win.setInputChannel(inputChannels[0]);
                 inputChannels[1].transferTo(outInputChannel);
-
                 mInputManager.registerInputChannel(win.mInputChannel, win.mInputWindowHandle);
             }
 
@@ -2166,10 +2176,7 @@
                 // The exit animation is running... wait for it!
                 win.mExiting = true;
                 win.mRemoveOnExit = true;
-                final DisplayContent displayContent = win.getDisplayContent();
-                if (displayContent != null) {
-                    displayContent.layoutNeeded = true;
-                }
+                win.setDisplayLayoutNeeded();
                 final boolean focusChanged = updateFocusedWindowLocked(
                         UPDATE_FOCUS_WILL_PLACE_SURFACES, false /*updateInputWindows*/);
                 mWindowPlacerLocked.performSurfacePlacement();
@@ -2198,7 +2205,7 @@
         removeWindowInnerLocked(win, true);
     }
 
-    void removeWindowInnerLocked(WindowState win, boolean performLayout) {
+    private void removeWindowInnerLocked(WindowState win, boolean performLayout) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2292,10 +2299,7 @@
             windows.remove(win);
             if (!mWindowPlacerLocked.isInLayout()) {
                 assignLayersLocked(windows);
-                final DisplayContent displayContent = win.getDisplayContent();
-                if (displayContent != null) {
-                    displayContent.layoutNeeded = true;
-                }
+                win.setDisplayLayoutNeeded();
                 if (performLayout) {
                     mWindowPlacerLocked.performSurfacePlacement();
                 }
@@ -2377,10 +2381,7 @@
                         w.mGivenVisibleInsets.scale(w.mGlobalScale);
                         w.mGivenTouchableRegion.scale(w.mGlobalScale);
                     }
-                    final DisplayContent displayContent = w.getDisplayContent();
-                    if (displayContent != null) {
-                        displayContent.layoutNeeded = true;
-                    }
+                    w.setDisplayLayoutNeeded();
                     mWindowPlacerLocked.performSurfacePlacement();
                 }
             }
@@ -2722,10 +2723,7 @@
                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
             }
 
-            final DisplayContent displayContent = win.getDisplayContent();
-            if (displayContent != null) {
-                displayContent.layoutNeeded = true;
-            }
+            win.setDisplayLayoutNeeded();
             win.mGivenInsetsPending = (flags&WindowManagerGlobal.RELAYOUT_INSETS_PENDING) != 0;
             configChanged = updateOrientationFromAppTokensLocked(false);
             mWindowPlacerLocked.performSurfacePlacement();
@@ -2818,10 +2816,7 @@
                         getDefaultDisplayContentLocked().pendingLayoutChanges |=
                                 WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                     }
-                    final DisplayContent displayContent = win.getDisplayContent();
-                    if (displayContent != null) {
-                        displayContent.layoutNeeded = true;
-                    }
+                    win.setDisplayLayoutNeeded();
                     mWindowPlacerLocked.requestTraversal();
                 }
             }
@@ -3260,8 +3255,7 @@
 
                 // if we're about to tear down this window and not seek for
                 // the behind activity, don't use it for orientation
-                if (!findingBehind
-                        && (!atoken.hidden && atoken.hiddenRequested)) {
+                if (!findingBehind && !atoken.hidden && atoken.hiddenRequested) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
                             + " -- going to hide");
                     continue;
@@ -3282,7 +3276,7 @@
                 }
 
                 // We ignore any hidden applications on the top.
-                if (atoken.hiddenRequested || atoken.willBeHidden) {
+                if (atoken.hiddenRequested) {
                     if (DEBUG_ORIENTATION) Slog.v(TAG, "Skipping " + atoken
                             + " -- hidden on top");
                     continue;
@@ -3778,7 +3772,6 @@
             if (!ttoken.hidden) {
                 wtoken.hidden = false;
                 wtoken.hiddenRequested = false;
-                wtoken.willBeHidden = false;
             }
             if (wtoken.clientHidden != ttoken.clientHidden) {
                 wtoken.clientHidden = ttoken.clientHidden;
@@ -3834,25 +3827,6 @@
         }
     }
 
-    @Override
-    public void setAppWillBeHidden(IBinder token) {
-        if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
-                "setAppWillBeHidden()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-
-        AppWindowToken wtoken;
-
-        synchronized(mWindowMap) {
-            wtoken = findAppWindowToken(token);
-            if (wtoken == null) {
-                Slog.w(TAG, "Attempted to set will be hidden of non-existing app token: " + token);
-                return;
-            }
-            wtoken.willBeHidden = true;
-        }
-    }
-
     public void setAppFullscreen(IBinder token, boolean toOpaque) {
         synchronized (mWindowMap) {
             AppWindowToken atoken = findAppWindowToken(token);
@@ -3889,7 +3863,6 @@
             wtoken.sendAppVisibilityToClients();
         }
 
-        wtoken.willBeHidden = false;
         // Allow for state changes and animation to be applied if:
         // * token is transitioning visibility state
         // * or the token was marked as hidden and is exiting before we had a chance to play the
@@ -3942,10 +3915,7 @@
                             }
                         }
                         changed = true;
-                        final DisplayContent displayContent = win.getDisplayContent();
-                        if (displayContent != null) {
-                            displayContent.layoutNeeded = true;
-                        }
+                        win.setDisplayLayoutNeeded();
                     }
                 } else if (win.isVisibleNow()) {
                     if (!runningAppAnimation) {
@@ -3959,10 +3929,7 @@
                         }
                     }
                     changed = true;
-                    final DisplayContent displayContent = win.getDisplayContent();
-                    if (displayContent != null) {
-                        displayContent.layoutNeeded = true;
-                    }
+                    win.setDisplayLayoutNeeded();
                 }
             }
 
@@ -4130,10 +4097,7 @@
                     }
                     w.mLastFreezeDuration = 0;
                     unfrozeWindows = true;
-                    final DisplayContent displayContent = w.getDisplayContent();
-                    if (displayContent != null) {
-                        displayContent.layoutNeeded = true;
-                    }
+                    w.setDisplayLayoutNeeded();
                 }
             }
             if (force || unfrozeWindows) {
@@ -4436,7 +4400,6 @@
         mInputMonitor.setUpdateInputWindowsNeededLw();
         mWindowPlacerLocked.performSurfacePlacement();
         mInputMonitor.updateInputWindowsLw(false /*force*/);
-
         //dump();
     }
 
@@ -4521,17 +4484,16 @@
                     }
                     stack.attachDisplayContent(displayContent);
                     displayContent.attachStack(stack, onTop);
-
                     moveStackWindowsLocked(displayContent);
                     final WindowList windows = displayContent.getWindowList();
                     for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                         windows.get(winNdx).reportResized();
                     }
-                    if (stack.isFullscreen()) {
+                    if (stack.getRawFullscreen()) {
                         return null;
                     }
                     Rect bounds = new Rect();
-                    stack.getBounds(bounds);
+                    stack.getRawBounds(bounds);
                     return bounds;
                 }
             }
@@ -4649,7 +4611,7 @@
                 stack.getDisplayContent().layoutNeeded = true;
                 mWindowPlacerLocked.performSurfacePlacement();
             }
-            return stack.isFullscreen();
+            return stack.getRawFullscreen();
         }
     }
 
@@ -6869,37 +6831,29 @@
     }
 
     boolean startMovingTask(IWindow window, float startX, float startY) {
-        WindowState callingWin = null;
+        WindowState win = null;
         synchronized (mWindowMap) {
-            callingWin = windowForClientLocked(null, window, false);
-            if (!startPositioningLocked(callingWin, false /*resize*/, startX, startY)) {
+            win = windowForClientLocked(null, window, false);
+            if (!startPositioningLocked(win, false /*resize*/, startX, startY)) {
                 return false;
             }
         }
         try {
-            mActivityManager.setFocusedTask(callingWin.getTask().mTaskId);
+            mActivityManager.setFocusedTask(win.getTask().mTaskId);
         } catch(RemoteException e) {}
         return true;
     }
 
     private void startResizingTask(DisplayContent displayContent, int startX, int startY) {
-        int taskId = -1;
-        AppWindowToken atoken = null;
+        WindowState win = null;
         synchronized (mWindowMap) {
-            taskId = displayContent.taskIdForControlPoint(startX, startY);
-            Task task = mTaskIdToTask.get(taskId);
-            if (task == null || task.mAppTokens == null) {
-                return;
-            }
-            AppTokenList tokens = task.mAppTokens;
-            atoken = tokens.get(tokens.size() - 1);
-            WindowState win = atoken.findMainWindow();
+            win = displayContent.findWindowForControlPoint(startX, startY);
             if (!startPositioningLocked(win, true /*resize*/, startX, startY)) {
                 return;
             }
         }
         try {
-            mActivityManager.setFocusedTask(taskId);
+            mActivityManager.setFocusedTask(win.getTask().mTaskId);
         } catch(RemoteException e) {}
     }
 
@@ -7144,22 +7098,7 @@
             final DisplayContent displayContent = getDisplayContentLocked(displayId);
             if (displayContent != null) {
                 mAnimator.addDisplayLocked(displayId);
-                synchronized(displayContent.mDisplaySizeLock) {
-                    // Bootstrap the default logical display from the display manager.
-                    final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-                    DisplayInfo newDisplayInfo = mDisplayManagerInternal.getDisplayInfo(displayId);
-                    if (newDisplayInfo != null) {
-                        displayInfo.copyFrom(newDisplayInfo);
-                    }
-                    displayContent.mInitialDisplayWidth = displayInfo.logicalWidth;
-                    displayContent.mInitialDisplayHeight = displayInfo.logicalHeight;
-                    displayContent.mInitialDisplayDensity = displayInfo.logicalDensityDpi;
-                    displayContent.mBaseDisplayWidth = displayContent.mInitialDisplayWidth;
-                    displayContent.mBaseDisplayHeight = displayContent.mInitialDisplayHeight;
-                    displayContent.mBaseDisplayDensity = displayContent.mInitialDisplayDensity;
-                    displayContent.mBaseDisplayRect.set(0, 0,
-                            displayContent.mBaseDisplayWidth, displayContent.mBaseDisplayHeight);
-                }
+                displayContent.initializeDisplayBaseInfo();
             }
         }
     }
@@ -7220,6 +7159,11 @@
         public static final int TAP_DOWN_OUTSIDE_TASK = 40;
         public static final int FINISH_TASK_POSITIONING = 41;
 
+        public static final int UPDATE_DOCKED_STACK_DIVIDER = 42;
+
+        public static final int RESIZE_STACK = 43;
+        public static final int RESIZE_TASK = 44;
+
         @Override
         public void handleMessage(Message msg) {
             if (DEBUG_WINDOW_TRACE) {
@@ -7759,6 +7703,29 @@
                     }
                 }
                 break;
+                case UPDATE_DOCKED_STACK_DIVIDER: {
+                    DisplayContent content = (DisplayContent) msg.obj;
+                    synchronized (mWindowMap) {
+                        content.mDividerControllerLocked.update();
+                    }
+                }
+                break;
+                case RESIZE_TASK: {
+                    try {
+                        mActivityManager.resizeTask(msg.arg1, (Rect) msg.obj, msg.arg2);
+                    } catch (RemoteException e) {
+                        // This will not happen since we are in the same process.
+                    }
+                }
+                break;
+                case RESIZE_STACK: {
+                    try {
+                        mActivityManager.resizeStack(msg.arg1, (Rect) msg.obj);
+                    } catch (RemoteException e) {
+                        // This will not happen since we are in the same process.
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG, "handleMessage: exit");
@@ -8300,7 +8267,7 @@
                 final int numTokens = tokens.size();
                 for (int tokenNdx = 0; tokenNdx < numTokens; ++tokenNdx) {
                     final AppWindowToken wtoken = tokens.get(tokenNdx);
-                    if (wtoken.mIsExiting) {
+                    if (wtoken.mIsExiting && !wtoken.mReplacingWindow) {
                         continue;
                     }
                     i = reAddAppWindowsLocked(displayContent, i, wtoken);
@@ -8370,6 +8337,13 @@
             } else if (wtoken != null) {
                 winAnimator.mAnimLayer =
                         w.mLayer + wtoken.mAppAnimator.animLayerAdjustment;
+                if (wtoken.mReplacingWindow && wtoken.mAnimateReplacingWindow) {
+                    // We know that we will be animating a relaunching window in the near future,
+                    // which will receive a z-order increase. We want the replaced window to
+                    // immediately receive the same treatment, e.g. to be above the dock divider.
+                    w.mLayer += TYPE_LAYER_OFFSET;
+                    winAnimator.mAnimLayer += TYPE_LAYER_OFFSET;
+                }
             } else {
                 winAnimator.mAnimLayer = w.mLayer;
             }
@@ -9892,6 +9866,12 @@
         return mWindowMap;
     }
 
+    /**
+     * Hint to a token that its activity will relaunch, which will trigger removal and addition of
+     * a window.
+     * @param token Application token for which the activity will be relaunched.
+     * @param animate Whether to animate the addition of the new window.
+     */
     public void setReplacingWindow(IBinder token, boolean animate) {
         synchronized (mWindowMap) {
             AppWindowToken appWindowToken = findAppWindowToken(token);
@@ -10081,8 +10061,6 @@
         @Override
         public void saveLastInputMethodWindowForTransition() {
             synchronized (mWindowMap) {
-                // TODO(multidisplay): Pass in the displayID.
-                DisplayContent displayContent = getDefaultDisplayContentLocked();
                 if (mInputMethodWindow != null) {
                     mPolicy.setLastInputMethodWindowLw(mInputMethodWindow, mInputMethodTarget);
                 }
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index a6478a0..55ddbc0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_DIM_BEHIND;
 import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED;
@@ -23,6 +24,7 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 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_WALLPAPER;
@@ -33,10 +35,12 @@
 import static com.android.server.wm.WindowManagerService.DEBUG_RESIZE;
 import static com.android.server.wm.WindowManagerService.DEBUG_VISIBILITY;
 
+import android.app.ActivityManager;
 import android.app.AppOpsManager;
 import android.os.PowerManager;
 import android.os.RemoteCallbackList;
 import android.os.SystemClock;
+import android.os.Trace;
 import android.os.WorkSource;
 import android.util.DisplayMetrics;
 import android.util.TimeUtils;
@@ -128,7 +132,6 @@
     boolean mAttachedHidden;    // is our parent window hidden?
     boolean mWallpaperVisible;  // for wallpaper, what was last vis report?
     boolean mDragResizing;
-    boolean mDragResizeChanging;
 
     RemoteCallbackList<IWindowFocusObserver> mFocusCallbacks;
 
@@ -707,6 +710,8 @@
             mContentFrame.set(mFrame);
             mVisibleFrame.set(mContentFrame);
             mStableFrame.set(mContentFrame);
+        } else if (mAttrs.type == TYPE_DOCK_DIVIDER) {
+            mDisplayContent.mDividerControllerLocked.positionDockedStackedDivider(mFrame);
         } else {
             mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
                     Math.max(mContentFrame.top, mFrame.top),
@@ -940,7 +945,6 @@
      */
     void getVisibleBounds(Rect bounds, boolean forTouch) {
         boolean intersectWithStackBounds = mAppToken != null && mAppToken.mCropWindowsToStack;
-        boolean isFreeform = false;
         bounds.setEmpty();
         mTmpRect.setEmpty();
         if (intersectWithStackBounds) {
@@ -952,13 +956,9 @@
             }
         }
 
-        final Task task = getTask();
-        if (task != null) {
-            task.getBounds(bounds);
-            isFreeform = task.inFreeformWorkspace();
-            if (intersectWithStackBounds) {
-                bounds.intersect(mTmpRect);
-            }
+        bounds.set(mVisibleFrame);
+        if (intersectWithStackBounds) {
+            bounds.intersect(mTmpRect);
         }
 
         if (bounds.isEmpty()) {
@@ -968,7 +968,7 @@
             }
             return;
         }
-        if (forTouch && isFreeform) {
+        if (forTouch && inFreeformWorkspace()) {
             final DisplayMetrics displayMetrics = getDisplayContent().getDisplayMetrics();
             final int delta = mService.dipToPixel(RESIZE_HANDLE_WIDTH_IN_DP, displayMetrics);
             bounds.inset(-delta, -delta);
@@ -1323,6 +1323,12 @@
         }
     }
 
+    void setDisplayLayoutNeeded() {
+        if (mDisplayContent != null) {
+            mDisplayContent.layoutNeeded = true;
+        }
+    }
+
     private class DeathRecipient implements IBinder.DeathRecipient {
         @Override
         public void binderDied() {
@@ -1467,10 +1473,7 @@
                 // We want the tag name to be somewhat stable so that it is easier to correlate
                 // in wake lock statistics.  So in particular, we don't want to include the
                 // window's hash code as in toString().
-                CharSequence tag = mAttrs.getTitle();
-                if (tag == null) {
-                    tag = mAttrs.packageName;
-                }
+                final CharSequence tag = getWindowTag();
                 mDrawLock = mService.mPowerManager.newWakeLock(
                         PowerManager.DRAW_WAKE_LOCK, "Window:" + tag);
                 mDrawLock.setReferenceCounted(false);
@@ -1607,6 +1610,7 @@
     }
 
     void reportResized() {
+        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "wm.reportResized_" + getWindowTag());
         try {
             if (DEBUG_RESIZE || DEBUG_ORIENTATION) Slog.v(TAG, "Reporting new frame to " + this
                     + ": " + mCompatFrame);
@@ -1672,6 +1676,7 @@
             mService.mPendingRemove.add(this);
             mService.mWindowPlacerLocked.requestTraversal();
         }
+        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
     }
 
     public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -1703,13 +1708,23 @@
     }
 
     boolean isDragResizeChanged() {
+        return mDragResizing != computeDragResizing();
+    }
+
+    private boolean computeDragResizing() {
         final Task task = getTask();
-        return task != null && mDragResizing != task.isDragResizing();
+        if (task == null) {
+            return false;
+        }
+        if (task.isDragResizing()) {
+            return true;
+        }
+        return mDisplayContent.mDividerControllerLocked.isResizing() &&
+                !task.inFreeformWorkspace() && !task.isFullscreen();
     }
 
     void setDragResizing() {
-        final Task task = getTask();
-        mDragResizing = task != null && task.isDragResizing();
+        mDragResizing = computeDragResizing();
     }
 
     boolean isDragResizing() {
@@ -1903,15 +1918,20 @@
 
     String makeInputChannelName() {
         return Integer.toHexString(System.identityHashCode(this))
-            + " " + mAttrs.getTitle();
+            + " " + getWindowTag();
+    }
+
+    private CharSequence getWindowTag() {
+        CharSequence tag = mAttrs.getTitle();
+        if (tag == null || tag.length() <= 0) {
+            tag = mAttrs.packageName;
+        }
+        return tag;
     }
 
     @Override
     public String toString() {
-        CharSequence title = mAttrs.getTitle();
-        if (title == null || title.length() <= 0) {
-            title = mAttrs.packageName;
-        }
+        final CharSequence title = getWindowTag();
         if (mStringNameCache == null || mLastTitle != title || mWasExiting != mExiting) {
             mLastTitle = title;
             mWasExiting = mExiting;
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 07e1fce..60bf571 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static com.android.server.wm.WindowManagerService.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerService.DEBUG_LAYERS;
@@ -868,14 +869,18 @@
                 mSurfaceW = width;
                 mSurfaceH = height;
 
-                final boolean isHwAccelerated = (attrs.flags &
-                        WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+                final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
                 final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
                 if (!PixelFormat.formatHasAlpha(attrs.format)
+                        // Don't make surface with surfaceInsets opaque as they display a
+                        // translucent shadow.
                         && attrs.surfaceInsets.left == 0
                         && attrs.surfaceInsets.top == 0
                         && attrs.surfaceInsets.right == 0
-                        && attrs.surfaceInsets.bottom  == 0) {
+                        && attrs.surfaceInsets.bottom == 0
+                        // Don't make surface opaque when resizing to reduce the amount of
+                        // artifacts shown in areas the app isn't drawing content to.
+                        && !w.isDragResizing()) {
                     flags |= SurfaceControl.OPAQUE;
                 }
 
@@ -1087,6 +1092,8 @@
                 mAnimator.getScreenRotationAnimationLocked(displayId);
         final boolean screenAnimation =
                 screenRotationAnimation != null && screenRotationAnimation.isAnimating();
+
+        mHasClipRect = false;
         if (selfTransformation || attachedTransformation != null
                 || appTransformation != null || screenAnimation) {
             // cache often used attributes locally
@@ -1165,7 +1172,6 @@
             // transforming since it is more important to have that
             // animation be smooth.
             mShownAlpha = mAlpha;
-            mHasClipRect = false;
             if (!mService.mLimitedAlphaCompositing
                     || (!PixelFormat.formatHasAlpha(mWin.mAttrs.format)
                     || (mWin.isIdentityMatrix(mDsDx, mDtDx, mDsDy, mDtDy)
@@ -1368,7 +1374,12 @@
         // so we need to translate to match the actual surface coordinates.
         clipRect.offset(attrs.surfaceInsets.left, attrs.surfaceInsets.top);
 
-        adjustCropToStackBounds(w, clipRect);
+        // We don't want to clip to stack bounds windows that are currently doing entrance
+        // animation. This is necessary for docking operation, otherwise the window will be
+        // suddenly cut off.
+        if (!mAnimator.mAnimating) {
+            adjustCropToStackBounds(w, clipRect);
+        }
 
         if (!clipRect.equals(mLastClipRect)) {
             mLastClipRect.set(clipRect);
@@ -1394,7 +1405,11 @@
 
     private void adjustCropToStackBounds(WindowState w, Rect clipRect) {
         final AppWindowToken appToken = w.mAppToken;
-        if (appToken != null && appToken.mCropWindowsToStack) {
+        // We don't apply the the stack bounds to the window that is being replaced, because it was
+        // living in a different stack. If we suddenly crop it to the new stack bounds, it might
+        // get cut off. We don't want it to happen, so we let it ignore the stack bounds until it
+        // gets removed. The window that will replace it will abide them.
+        if (appToken != null && appToken.mCropWindowsToStack && !appToken.mReplacingWindow) {
             TaskStack stack = w.getTask().mStack;
             stack.getBounds(mTmpStackBounds);
             final int surfaceX = (int) mSurfaceX;
@@ -1707,8 +1722,7 @@
             return false;
         }
         final LayoutParams attrs = mWin.getAttrs();
-        final boolean isHwAccelerated = (attrs.flags &
-                WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED) != 0;
+        final boolean isHwAccelerated = (attrs.flags & FLAG_HARDWARE_ACCELERATED) != 0;
         final int format = isHwAccelerated ? PixelFormat.TRANSLUCENT : attrs.format;
         if (format == mSurfaceFormat) {
             setOpaqueLocked(!PixelFormat.formatHasAlpha(attrs.format));
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index e77ebe7..df0a1c9 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -47,6 +47,7 @@
 import android.os.SystemClock;
 import android.os.Trace;
 import android.provider.Settings;
+import android.util.ArraySet;
 import android.util.Slog;
 import android.view.Display;
 import android.view.DisplayInfo;
@@ -966,6 +967,7 @@
         }
 
         mService.mPolicy.finishLayoutLw();
+        mService.mH.obtainMessage(UPDATE_DOCKED_STACK_DIVIDER, displayContent).sendToTarget();
     }
 
     /**
@@ -1228,11 +1230,15 @@
         final WindowState oldWallpaper =
                 mWallpaperControllerLocked.isWallpaperTargetAnimating()
                         ? null : wallpaperTarget;
+        final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
+        final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                 "New wallpaper target=" + wallpaperTarget
                         + ", oldWallpaper=" + oldWallpaper
                         + ", lower target=" + lowerWallpaperTarget
-                        + ", upper target=" + upperWallpaperTarget);
+                        + ", upper target=" + upperWallpaperTarget
+                        + ", openingApps=" + openingApps
+                        + ", closingApps=" + closingApps);
         mService.mAnimateWallpaperWithTarget = false;
         if (closingAppHasWallpaper && openingAppHasWallpaper) {
             if (DEBUG_APP_TRANSITIONS)
@@ -1251,15 +1257,16 @@
             }
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit: " + AppTransition.appTransitionToString(transit));
-        } else if ((oldWallpaper != null) && !mService.mOpeningApps.isEmpty()
-                && !mService.mOpeningApps.contains(oldWallpaper.mAppToken)) {
-            // We are transitioning from an activity with
-            // a wallpaper to one without.
+        } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
+                && !openingApps.contains(oldWallpaper.mAppToken)
+                && closingApps.contains(oldWallpaper.mAppToken)) {
+            // We are transitioning from an activity with a wallpaper to one without.
             transit = AppTransition.TRANSIT_WALLPAPER_CLOSE;
             if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                     "New transit away from wallpaper: "
                     + AppTransition.appTransitionToString(transit));
-        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()) {
+        } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw() &&
+                openingApps.contains(wallpaperTarget.mAppToken)) {
             // We are transitioning from an activity without
             // a wallpaper to now showing the wallpaper
             transit = AppTransition.TRANSIT_WALLPAPER_OPEN;
diff --git a/services/core/jni/com_android_server_AlarmManagerService.cpp b/services/core/jni/com_android_server_AlarmManagerService.cpp
index 3fd0f84..5cbb277 100644
--- a/services/core/jni/com_android_server_AlarmManagerService.cpp
+++ b/services/core/jni/com_android_server_AlarmManagerService.cpp
@@ -460,7 +460,7 @@
     return result;
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"init", "()J", (void*)android_server_AlarmManagerService_init},
     {"close", "(J)V", (void*)android_server_AlarmManagerService_close},
diff --git a/services/core/jni/com_android_server_AssetAtlasService.cpp b/services/core/jni/com_android_server_AssetAtlasService.cpp
index 8f4fb51..ed79ceb 100644
--- a/services/core/jni/com_android_server_AssetAtlasService.cpp
+++ b/services/core/jni/com_android_server_AssetAtlasService.cpp
@@ -204,7 +204,7 @@
 
 const char* const kClassPathName = "com/android/server/AssetAtlasService";
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     { "nUploadAtlas", "(Landroid/view/GraphicBuffer;Landroid/graphics/Bitmap;)Z",
             (void*) com_android_server_AssetAtlasService_upload },
 };
diff --git a/services/core/jni/com_android_server_ConsumerIrService.cpp b/services/core/jni/com_android_server_ConsumerIrService.cpp
index f5121cd..7104870 100644
--- a/services/core/jni/com_android_server_ConsumerIrService.cpp
+++ b/services/core/jni/com_android_server_ConsumerIrService.cpp
@@ -100,7 +100,7 @@
     return freqsOut.getJavaArray();
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "halOpen", "()J", (void *)halOpen },
     { "halTransmit", "(JI[I)I", (void *)halTransmit },
     { "halGetCarrierFrequencies", "(J)[I", (void *)halGetCarrierFrequencies},
diff --git a/services/core/jni/com_android_server_PersistentDataBlockService.cpp b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
index 4ccfa56..06de592 100644
--- a/services/core/jni/com_android_server_PersistentDataBlockService.cpp
+++ b/services/core/jni/com_android_server_PersistentDataBlockService.cpp
@@ -97,7 +97,7 @@
         return wipe_block_device(fd);
     }
 
-    static JNINativeMethod sMethods[] = {
+    static const JNINativeMethod sMethods[] = {
          /* name, signature, funcPtr */
         {"nativeGetBlockDeviceSize", "(Ljava/lang/String;)J", (void*)com_android_server_PersistentDataBlockService_getBlockDeviceSize},
         {"nativeWipe", "(Ljava/lang/String;)I", (void*)com_android_server_PersistentDataBlockService_wipe},
diff --git a/services/core/jni/com_android_server_SerialService.cpp b/services/core/jni/com_android_server_SerialService.cpp
index d48d159..1bd7a59 100644
--- a/services/core/jni/com_android_server_SerialService.cpp
+++ b/services/core/jni/com_android_server_SerialService.cpp
@@ -55,7 +55,7 @@
 }
 
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "native_open",                "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
                                     (void*)android_server_SerialService_open },
 };
diff --git a/services/core/jni/com_android_server_SystemServer.cpp b/services/core/jni/com_android_server_SystemServer.cpp
index 64514a9..c7d6b95 100644
--- a/services/core/jni/com_android_server_SystemServer.cpp
+++ b/services/core/jni/com_android_server_SystemServer.cpp
@@ -37,7 +37,7 @@
 /*
  * JNI registration.
  */
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     /* name, signature, funcPtr */
     { "startSensorService", "()V", (void*) android_server_SystemServer_startSensorService },
 };
diff --git a/services/core/jni/com_android_server_UsbDeviceManager.cpp b/services/core/jni/com_android_server_UsbDeviceManager.cpp
index a1bff9d..3733a55 100644
--- a/services/core/jni/com_android_server_UsbDeviceManager.cpp
+++ b/services/core/jni/com_android_server_UsbDeviceManager.cpp
@@ -118,7 +118,7 @@
     return result;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "nativeGetAccessoryStrings",  "()[Ljava/lang/String;",
                                     (void*)android_server_UsbDeviceManager_getAccessoryStrings },
     { "nativeOpenAccessory",        "()Landroid/os/ParcelFileDescriptor;",
diff --git a/services/core/jni/com_android_server_UsbHostManager.cpp b/services/core/jni/com_android_server_UsbHostManager.cpp
index d8c172f..795f6aa 100644
--- a/services/core/jni/com_android_server_UsbHostManager.cpp
+++ b/services/core/jni/com_android_server_UsbHostManager.cpp
@@ -186,7 +186,7 @@
         gParcelFileDescriptorOffsets.mConstructor, fileDescriptor);
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "monitorUsbHostBus", "()V", (void*)android_server_UsbHostManager_monitorUsbHostBus },
     { "nativeOpenDevice",  "(Ljava/lang/String;)Landroid/os/ParcelFileDescriptor;",
                                   (void*)android_server_UsbHostManager_openDevice },
diff --git a/services/core/jni/com_android_server_VibratorService.cpp b/services/core/jni/com_android_server_VibratorService.cpp
index fb1166b..64278ed 100644
--- a/services/core/jni/com_android_server_VibratorService.cpp
+++ b/services/core/jni/com_android_server_VibratorService.cpp
@@ -46,7 +46,7 @@
     vibrator_off();
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "vibratorExists", "()Z", (void*)vibratorExists },
     { "vibratorOn", "(J)V", (void*)vibratorOn },
     { "vibratorOff", "()V", (void*)vibratorOff }
diff --git a/services/core/jni/com_android_server_am_BatteryStatsService.cpp b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
index dfc5ef6..5c43659 100644
--- a/services/core/jni/com_android_server_am_BatteryStatsService.cpp
+++ b/services/core/jni/com_android_server_am_BatteryStatsService.cpp
@@ -170,7 +170,7 @@
     return mergedreasonpos - mergedreason;
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "nativeWaitWakeup", "(Ljava/nio/ByteBuffer;)I", (void*)nativeWaitWakeup },
 };
 
diff --git a/services/core/jni/com_android_server_connectivity_Vpn.cpp b/services/core/jni/com_android_server_connectivity_Vpn.cpp
index 7faeb49..2d0dfd2 100644
--- a/services/core/jni/com_android_server_connectivity_Vpn.cpp
+++ b/services/core/jni/com_android_server_connectivity_Vpn.cpp
@@ -350,7 +350,7 @@
 
 //------------------------------------------------------------------------------
 
-static JNINativeMethod gMethods[] = {
+static const JNINativeMethod gMethods[] = {
     {"jniCreate", "(I)I", (void *)create},
     {"jniGetName", "(I)Ljava/lang/String;", (void *)getName},
     {"jniSetAddresses", "(Ljava/lang/String;Ljava/lang/String;)I", (void *)setAddresses},
diff --git a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
index f2d0f06..b72cf4d 100644
--- a/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
+++ b/services/core/jni/com_android_server_hdmi_HdmiCecController.cpp
@@ -384,7 +384,7 @@
     return controller->isConnected(port) ? JNI_TRUE : JNI_FALSE ;
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
       "(Lcom/android/server/hdmi/HdmiCecController;Landroid/os/MessageQueue;)J",
diff --git a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
index 11388d8..bdc109d 100644
--- a/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputApplicationHandle.cpp
@@ -120,7 +120,7 @@
 }
 
 
-static JNINativeMethod gInputApplicationHandleMethods[] = {
+static const JNINativeMethod gInputApplicationHandleMethods[] = {
     /* name, signature, funcPtr */
     { "nativeDispose", "()V",
             (void*) android_server_InputApplicationHandle_nativeDispose },
diff --git a/services/core/jni/com_android_server_input_InputManagerService.cpp b/services/core/jni/com_android_server_input_InputManagerService.cpp
index e29d0a9..1d4f047 100644
--- a/services/core/jni/com_android_server_input_InputManagerService.cpp
+++ b/services/core/jni/com_android_server_input_InputManagerService.cpp
@@ -1369,7 +1369,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gInputManagerMethods[] = {
+static const JNINativeMethod gInputManagerMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit",
             "(Lcom/android/server/input/InputManagerService;Landroid/content/Context;Landroid/os/MessageQueue;)J",
diff --git a/services/core/jni/com_android_server_input_InputWindowHandle.cpp b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
index 01c51cf..92ef7f1 100644
--- a/services/core/jni/com_android_server_input_InputWindowHandle.cpp
+++ b/services/core/jni/com_android_server_input_InputWindowHandle.cpp
@@ -210,7 +210,7 @@
 }
 
 
-static JNINativeMethod gInputWindowHandleMethods[] = {
+static const JNINativeMethod gInputWindowHandleMethods[] = {
     /* name, signature, funcPtr */
     { "nativeDispose", "()V",
             (void*) android_server_InputWindowHandle_nativeDispose },
diff --git a/services/core/jni/com_android_server_lights_LightsService.cpp b/services/core/jni/com_android_server_lights_LightsService.cpp
index b2b2783..3f074f5 100644
--- a/services/core/jni/com_android_server_lights_LightsService.cpp
+++ b/services/core/jni/com_android_server_lights_LightsService.cpp
@@ -126,7 +126,7 @@
     }
 }
 
-static JNINativeMethod method_table[] = {
+static const JNINativeMethod method_table[] = {
     { "init_native", "()J", (void*)init_native },
     { "finalize_native", "(J)V", (void*)finalize_native },
     { "setLight_native", "(JIIIIII)V", (void*)setLight_native },
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index c0a0c9c..774577d 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -1023,7 +1023,7 @@
   env->ReleaseIntArrayElements(geofenceIdsArray, geofenceIds, 0 /*mode*/);
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
   //{"name", "signature", functionPointer }
   {"nativeClassInit", "()V", reinterpret_cast<void*>(ClassInit)},
   {"nativeInit", "()V", reinterpret_cast<void*>(Init)},
diff --git a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
index 5c27b1f..b8d4196da 100644
--- a/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GpsLocationProvider.cpp
@@ -1434,7 +1434,7 @@
     env->ReleaseStringUTFChars(config_content, data);
 }
 
-static JNINativeMethod sMethods[] = {
+static const JNINativeMethod sMethods[] = {
      /* name, signature, funcPtr */
     {"class_init_native", "()V", (void *)android_location_GpsLocationProvider_class_init_native},
     {"native_is_supported", "()Z", (void*)android_location_GpsLocationProvider_is_supported},
diff --git a/services/core/jni/com_android_server_power_PowerManagerService.cpp b/services/core/jni/com_android_server_power_PowerManagerService.cpp
index 1662755..2fdb8e2 100644
--- a/services/core/jni/com_android_server_power_PowerManagerService.cpp
+++ b/services/core/jni/com_android_server_power_PowerManagerService.cpp
@@ -166,7 +166,7 @@
 
 // ----------------------------------------------------------------------------
 
-static JNINativeMethod gPowerManagerServiceMethods[] = {
+static const JNINativeMethod gPowerManagerServiceMethods[] = {
     /* name, signature, funcPtr */
     { "nativeInit", "()V",
             (void*) nativeInit },
diff --git a/services/core/jni/com_android_server_tv_TvInputHal.cpp b/services/core/jni/com_android_server_tv_TvInputHal.cpp
index 507bc9c..89b2a47 100644
--- a/services/core/jni/com_android_server_tv_TvInputHal.cpp
+++ b/services/core/jni/com_android_server_tv_TvInputHal.cpp
@@ -662,7 +662,7 @@
     delete tvInputHal;
 }
 
-static JNINativeMethod gTvInputHalMethods[] = {
+static const JNINativeMethod gTvInputHalMethods[] = {
     /* name, signature, funcPtr */
     { "nativeOpen", "(Landroid/os/MessageQueue;)J",
             (void*) nativeOpen },
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index b0a04c7..2dd7cde 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -29,6 +29,7 @@
 import android.Manifest.permission;
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.accounts.AccountManager;
+import android.annotation.NonNull;
 import android.app.Activity;
 import android.app.ActivityManagerNative;
 import android.app.AlarmManager;
@@ -54,6 +55,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
@@ -76,7 +78,6 @@
 import android.os.Looper;
 import android.os.PersistableBundle;
 import android.os.PowerManager;
-import android.os.PowerManager.WakeLock;
 import android.os.PowerManagerInternal;
 import android.os.Process;
 import android.os.RecoverySystem;
@@ -269,17 +270,12 @@
             | DevicePolicyManager.KEYGUARD_DISABLE_UNREDACTED_NOTIFICATIONS;
 
     final Context mContext;
-    final PackageManager mPackageManager;
+    final Injector mInjector;
+    final IPackageManager mIPackageManager;
     final UserManager mUserManager;
-    final PowerManager.WakeLock mWakeLock;
 
     final LocalService mLocalService;
 
-    final PowerManagerInternal mPowerManagerInternal;
-
-    final IWindowManager mIWindowManager;
-    final NotificationManager mNotificationManager;
-
     // Stores and loads state on device and profile owners.
     private final Owners mOwners;
 
@@ -995,7 +991,6 @@
         boolean removed = false;
         if (DBG) Slog.d(LOG_TAG, "Handling package changes for user " + userHandle);
         DevicePolicyData policy = getUserData(userHandle);
-        IPackageManager pm = AppGlobals.getPackageManager();
         synchronized (this) {
             for (int i = policy.mAdminList.size() - 1; i >= 0; i--) {
                 ActiveAdmin aa = policy.mAdminList.get(i);
@@ -1004,9 +999,9 @@
                     // then check if the package and receiver still exist.
                     final String adminPackage = aa.info.getPackageName();
                     if (packageName == null || packageName.equals(adminPackage)) {
-                        if (pm.getPackageInfo(adminPackage, 0, userHandle) == null
-                                || pm.getReceiverInfo(aa.info.getComponent(), 0, userHandle)
-                                    == null) {
+                        if (mIPackageManager.getPackageInfo(adminPackage, 0, userHandle) == null
+                                || mIPackageManager.getReceiverInfo(
+                                    aa.info.getComponent(), 0, userHandle) == null) {
                             removed = true;
                             policy.mAdminList.remove(i);
                             policy.mAdminMap.remove(aa.info.getComponent());
@@ -1027,7 +1022,7 @@
                     || packageName.equals(policy.mDelegatedCertInstallerPackage))) {
                 try {
                     // Check if delegated cert installer package is removed.
-                    if (pm.getPackageInfo(
+                    if (mIPackageManager.getPackageInfo(
                             policy.mDelegatedCertInstallerPackage, 0, userHandle) == null) {
                         policy.mDelegatedCertInstallerPackage = null;
                         saveSettingsLocked(policy.mUserHandle);
@@ -1039,120 +1034,146 @@
         }
     }
 
-    /** Unit test will override it to inject a mock. */
+    /**
+     * Unit test will subclass it to inject mocks.
+     */
     @VisibleForTesting
-    Owners newOwners() {
-        return new Owners(mContext);
-    }
+    static class Injector {
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    UserManager getUserManager() {
-        return UserManager.get(mContext);
-    }
+        private final Context mContext;
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    PackageManager getPackageManager() {
-        return mContext.getPackageManager();
-    }
+        Injector(Context context) {
+            mContext = context;
+        }
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    NotificationManager getNotificationManager() {
-        return mContext.getSystemService(NotificationManager.class);
-    }
+        Owners newOwners() {
+            return new Owners(mContext);
+        }
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    PowerManagerInternal getPowerManagerInternal() {
-        return LocalServices.getService(PowerManagerInternal.class);
-    }
+        UserManager getUserManager() {
+            return UserManager.get(mContext);
+        }
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    IWindowManager newIWindowManager() {
-        return IWindowManager.Stub.asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
-    }
+        NotificationManager getNotificationManager() {
+            return mContext.getSystemService(NotificationManager.class);
+        }
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    IActivityManager getIActivityManager() {
-        return ActivityManagerNative.getDefault();
-    }
+        PowerManagerInternal getPowerManagerInternal() {
+            return LocalServices.getService(PowerManagerInternal.class);
+        }
 
-    /** Unit test will override it to inject a mock. */
-    @VisibleForTesting
-    LockPatternUtils newLockPatternUtils(Context context) {
-        return new LockPatternUtils(context);
-    }
+        IWindowManager getIWindowManager() {
+            return IWindowManager.Stub
+                    .asInterface(ServiceManager.getService(Context.WINDOW_SERVICE));
+        }
 
-    /** Unit test will override it to inject. */
-    @VisibleForTesting
-    Looper getMyLooper() {
-        return Looper.myLooper();
-    }
+        IActivityManager getIActivityManager() {
+            return ActivityManagerNative.getDefault();
+        }
 
-    @VisibleForTesting
-    long binderClearCallingIdentity() {
-        return Binder.clearCallingIdentity();
-    }
+        IPackageManager getIPackageManager() {
+            return AppGlobals.getPackageManager();
+        }
 
-    @VisibleForTesting
-    void binderRestoreCallingIdentity(long token) {
-        Binder.restoreCallingIdentity(token);
-    }
+        IBackupManager getIBackupManager() {
+            return IBackupManager.Stub.asInterface(
+                    ServiceManager.getService(Context.BACKUP_SERVICE));
+        }
 
-    @VisibleForTesting
-    int binderGetCallingUid() {
-        return Binder.getCallingUid();
-    }
+        IAudioService getIAudioService() {
+            return IAudioService.Stub.asInterface(ServiceManager.getService(Context.AUDIO_SERVICE));
+        }
 
-    @VisibleForTesting
-    int binderGetCallingPid() {
-        return Binder.getCallingPid();
-    }
+        LockPatternUtils newLockPatternUtils() {
+            return new LockPatternUtils(mContext);
+        }
 
-    @VisibleForTesting
-    UserHandle binderGetCallingUserHandle() {
-        return Binder.getCallingUserHandle();
-    }
+        Looper getMyLooper() {
+            return Looper.myLooper();
+        }
 
-    @VisibleForTesting
-    boolean binderIsCallingUidMyUid() {
-        return getCallingUid() == Process.myUid();
-    }
+        long binderClearCallingIdentity() {
+            return Binder.clearCallingIdentity();
+        }
 
-    @VisibleForTesting
-    File environmentGetUserSystemDirectory(int userId) {
-        return Environment.getUserSystemDirectory(userId);
-    }
+        void binderRestoreCallingIdentity(long token) {
+            Binder.restoreCallingIdentity(token);
+        }
 
-    @VisibleForTesting
-    WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) {
-        return mContext.getSystemService(PowerManager.class).newWakeLock(levelAndFlags, tag);
-    }
+        int binderGetCallingUid() {
+            return Binder.getCallingUid();
+        }
 
-    @VisibleForTesting
-    void powerManagerGoToSleep(long time, int reason, int flags) {
-        mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
+        int binderGetCallingPid() {
+            return Binder.getCallingPid();
+        }
+
+        UserHandle binderGetCallingUserHandle() {
+            return Binder.getCallingUserHandle();
+        }
+
+        boolean binderIsCallingUidMyUid() {
+            return getCallingUid() == Process.myUid();
+        }
+
+        File environmentGetUserSystemDirectory(int userId) {
+            return Environment.getUserSystemDirectory(userId);
+        }
+
+        void powerManagerGoToSleep(long time, int reason, int flags) {
+            mContext.getSystemService(PowerManager.class).goToSleep(time, reason, flags);
+        }
+
+        boolean systemPropertiesGetBoolean(String key, boolean def) {
+            return SystemProperties.getBoolean(key, def);
+        }
+
+        long systemPropertiesGetLong(String key, long def) {
+            return SystemProperties.getLong(key, def);
+        }
+
+        String systemPropertiesGet(String key, String def) {
+            return SystemProperties.get(key, def);
+        }
+
+        String systemPropertiesGet(String key) {
+            return SystemProperties.get(key);
+        }
+
+        void systemPropertiesSet(String key, String value) {
+            SystemProperties.set(key, value);
+        }
+
+        boolean userManagerIsSplitSystemUser() {
+            return UserManager.isSplitSystemUser();
+        }
+
+        String getDevicePolicyFilePathForSystemUser() {
+            return "/data/system/";
+        }
     }
 
     /**
      * Instantiates the service.
      */
     public DevicePolicyManagerService(Context context) {
-        mContext = context;
-        mHandler = new Handler(getMyLooper());
-        mOwners = newOwners();
-        mUserManager = getUserManager();
-        mPackageManager = getPackageManager();
-        mHasFeature = mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
-        mPowerManagerInternal = getPowerManagerInternal();
-        mWakeLock = powerManagerNewWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "DPM");
-        mIWindowManager = newIWindowManager();
-        mNotificationManager = getNotificationManager();
+        this(new Injector(context));
+    }
+
+    @VisibleForTesting
+    DevicePolicyManagerService(Injector injector) {
+        mInjector = injector;
+        mContext = Preconditions.checkNotNull(injector.mContext);
+        mHandler = new Handler(Preconditions.checkNotNull(injector.getMyLooper()));
+        mOwners = Preconditions.checkNotNull(injector.newOwners());
+
+        mUserManager = Preconditions.checkNotNull(injector.getUserManager());
+        mIPackageManager = Preconditions.checkNotNull(injector.getIPackageManager());
+
         mLocalService = new LocalService();
+
+        mHasFeature = mContext.getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN);
         if (!mHasFeature) {
             // Skip the rest of the initialization
             return;
@@ -1164,35 +1185,27 @@
         filter.addAction(Intent.ACTION_USER_STARTED);
         filter.addAction(KeyChain.ACTION_STORAGE_CHANGED);
         filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
-        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
         filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
         filter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
         filter.addAction(Intent.ACTION_PACKAGE_ADDED);
         filter.addDataScheme("package");
-        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
         filter = new IntentFilter();
         filter.addAction(Intent.ACTION_MANAGED_PROFILE_ADDED);
-        context.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
+        mContext.registerReceiverAsUser(mReceiver, UserHandle.ALL, filter, null, mHandler);
 
         LocalServices.addService(DevicePolicyManagerInternal.class, mLocalService);
     }
 
     /**
-     * We need it for testing to allow accessing context from the test-only subclass while this
-     * class's constructor is still running.
-     */
-    @VisibleForTesting
-    Context getContext() {
-        return mContext;
-    }
-
-    /**
      * Creates and loads the policy data from xml.
      * @param userHandle the user for whom to load the policy data
      * @return
      */
+    @NonNull
     DevicePolicyData getUserData(int userHandle) {
         synchronized (this) {
             DevicePolicyData policy = mUserData.get(userHandle);
@@ -1216,11 +1229,11 @@
      * @return
      */
     DevicePolicyData getUserDataUnchecked(int userHandle) {
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             return getUserData(userHandle);
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -1237,7 +1250,7 @@
             if (policy != null) {
                 mUserData.remove(userHandle);
             }
-            File policyFile = new File(environmentGetUserSystemDirectory(userHandle),
+            File policyFile = new File(mInjector.environmentGetUserSystemDirectory(userHandle),
                     DEVICE_POLICIES_XML);
             policyFile.delete();
             Slog.i(LOG_TAG, "Removed device policy file " + policyFile.getAbsolutePath());
@@ -1277,7 +1290,7 @@
             alarmTime = now + alarmInterval;
         }
 
-        long token = binderClearCallingIdentity();
+        long token = mInjector.binderClearCallingIdentity();
         try {
             AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
             PendingIntent pi = PendingIntent.getBroadcastAsUser(context, REQUEST_EXPIRE_PASSWORD,
@@ -1289,7 +1302,7 @@
                 am.set(AlarmManager.RTC, alarmTime, pi);
             }
         } finally {
-            binderRestoreCallingIdentity(token);
+            mInjector.binderRestoreCallingIdentity(token);
         }
     }
 
@@ -1305,7 +1318,7 @@
 
     ActiveAdmin getActiveAdminForCallerLocked(ComponentName who, int reqPolicy)
             throws SecurityException {
-        final int callingUid = binderGetCallingUid();
+        final int callingUid = mInjector.binderGetCallingUid();
 
         ActiveAdmin result = getActiveAdminWithPolicyForUidLocked(who, reqPolicy, callingUid);
         if (result != null) {
@@ -1329,7 +1342,7 @@
                     + admin.info.getTagForPolicy(reqPolicy));
         } else {
             throw new SecurityException("No active admin owned by uid "
-                    + binderGetCallingUid() + " for policy #" + reqPolicy);
+                    + mInjector.binderGetCallingUid() + " for policy #" + reqPolicy);
         }
     }
 
@@ -1345,7 +1358,7 @@
             }
             if (admin.getUid() != uid) {
                 throw new SecurityException("Admin " + who + " is not owned by uid "
-                        + binderGetCallingUid());
+                        + mInjector.binderGetCallingUid());
             }
             if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
                 return admin;
@@ -1509,17 +1522,12 @@
 
     private JournaledFile makeJournaledFile(int userHandle) {
         final String base = userHandle == UserHandle.USER_SYSTEM
-                ? getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
-                : new File(environmentGetUserSystemDirectory(userHandle), DEVICE_POLICIES_XML)
-                        .getAbsolutePath();
+                ? mInjector.getDevicePolicyFilePathForSystemUser() + DEVICE_POLICIES_XML
+                : new File(mInjector.environmentGetUserSystemDirectory(userHandle),
+                        DEVICE_POLICIES_XML).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
     }
 
-    @VisibleForTesting
-    String getDevicePolicyFilePathForSystemUser() {
-        return "/data/system/";
-    }
-
     private void saveSettingsLocked(int userHandle) {
         DevicePolicyData policy = getUserData(userHandle);
         JournaledFile journal = makeJournaledFile(userHandle);
@@ -1630,11 +1638,11 @@
     private void sendChangedNotification(int userHandle) {
         Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         intent.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             mContext.sendBroadcastAsUser(intent, new UserHandle(userHandle));
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -1766,9 +1774,9 @@
         // sufficiently what is currently set.  Note that this is only
         // a sanity check in case the two get out of sync; this should
         // never normally happen.
-        final long identity = binderClearCallingIdentity();
+        final long identity = mInjector.binderClearCallingIdentity();
         try {
-            LockPatternUtils utils = newLockPatternUtils(mContext);
+            LockPatternUtils utils = mInjector.newLockPatternUtils();
             if (utils.getActivePasswordQuality(userHandle) < policy.mActivePasswordQuality) {
                 Slog.w(LOG_TAG, "Active password quality 0x"
                         + Integer.toHexString(policy.mActivePasswordQuality)
@@ -1784,7 +1792,7 @@
                 policy.mActivePasswordNonLetter = 0;
             }
         } finally {
-            binderRestoreCallingIdentity(identity);
+            mInjector.binderRestoreCallingIdentity(identity);
         }
 
         validatePasswordOwnerLocked(policy);
@@ -1798,26 +1806,26 @@
     }
 
     private void updateLockTaskPackagesLocked(List<String> packages, int userId) {
-        IActivityManager am = getIActivityManager();
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
-            am.updateLockTaskPackages(userId, packages.toArray(new String[packages.size()]));
+            mInjector.getIActivityManager()
+                    .updateLockTaskPackages(userId, packages.toArray(new String[packages.size()]));
         } catch (RemoteException e) {
             // Not gonna happen.
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
     private void updateDeviceOwnerLocked() {
-        IActivityManager am = getIActivityManager();
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
-            am.updateDeviceOwner(getDeviceOwner());
+            mInjector.getIActivityManager()
+                    .updateDeviceOwner(getDeviceOwner());
         } catch (RemoteException e) {
             // Not gonna happen.
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -1862,17 +1870,17 @@
         // Ensure the status of the camera is synced down to the system. Interested native services
         // should monitor this value and act accordingly.
         String cameraPropertyForUser = SYSTEM_PROP_DISABLE_CAMERA_PREFIX + policy.mUserHandle;
-        boolean systemState = SystemProperties.getBoolean(cameraPropertyForUser, false);
+        boolean systemState = mInjector.systemPropertiesGetBoolean(cameraPropertyForUser, false);
         boolean cameraDisabled = getCameraDisabled(null, policy.mUserHandle);
         if (cameraDisabled != systemState) {
-            long token = binderClearCallingIdentity();
+            long token = mInjector.binderClearCallingIdentity();
             try {
                 String value = cameraDisabled ? "1" : "0";
                 if (DBG) Slog.v(LOG_TAG, "Change in camera state ["
                         + cameraPropertyForUser + "] = " + value);
-                SystemProperties.set(cameraPropertyForUser, value);
+                mInjector.systemPropertiesSet(cameraPropertyForUser, value);
             } finally {
-                binderRestoreCallingIdentity(token);
+                mInjector.binderRestoreCallingIdentity(token);
             }
         }
     }
@@ -1912,14 +1920,13 @@
 
     private void ensureDeviceOwnerUserStarted() {
         if (mOwners.hasDeviceOwner()) {
-            final IActivityManager am = getIActivityManager();
             final int userId = mOwners.getDeviceOwnerUserId();
             if (VERBOSE_LOG) {
                 Log.v(LOG_TAG, "Starting non-system DO user: " + userId);
             }
             if (userId != UserHandle.USER_SYSTEM) {
                 try {
-                    am.startUserInBackground(userId);
+                    mInjector.getIActivityManager().startUserInBackground(userId);
 
                     // STOPSHIP Prevent the DO user from being killed.
 
@@ -2020,7 +2027,7 @@
                 Log.e(LOG_TAG, "Could not connect to KeyChain service", e);
             }
             if (!hasCert) {
-                mNotificationManager.cancelAsUser(
+                mInjector.getNotificationManager().cancelAsUser(
                         null, MONITORING_CERT_NOTIFICATION_ID, userHandle);
                 return;
             }
@@ -2065,7 +2072,7 @@
                         com.android.internal.R.color.system_notification_accent_color))
                 .build();
 
-            mNotificationManager.notifyAsUser(
+            mInjector.getNotificationManager().notifyAsUser(
                     null, MONITORING_CERT_NOTIFICATION_ID, noti, userHandle);
         }
     }
@@ -2094,7 +2101,7 @@
             throw new IllegalArgumentException("Bad admin: " + adminReceiver);
         }
         synchronized (this) {
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
                 if (!refreshing
                         && getActiveAdminUncheckedLocked(adminReceiver, userHandle) != null) {
@@ -2121,7 +2128,7 @@
                 sendAdminCommandLocked(newAdmin, DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
                         onEnableData, null);
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -2215,7 +2222,7 @@
             if (admin == null) {
                 return;
             }
-            if (admin.getUid() != binderGetCallingUid()) {
+            if (admin.getUid() != mInjector.binderGetCallingUid()) {
                 // Active device owners must remain active admins.
                 if (isDeviceOwner(adminReceiver.getPackageName())) {
                     return;
@@ -2223,11 +2230,11 @@
                 mContext.enforceCallingOrSelfPermission(
                         android.Manifest.permission.MANAGE_DEVICE_ADMINS, null);
             }
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
                 removeActiveAdminLocked(adminReceiver, userHandle);
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -2497,7 +2504,7 @@
                     || activeAdmin.crossProfileWidgetProviders.isEmpty()) {
                 return null;
             }
-            if (binderIsCallingUidMyUid()) {
+            if (mInjector.binderIsCallingUidMyUid()) {
                 return new ArrayList<>(activeAdmin.crossProfileWidgetProviders);
             } else {
                 return activeAdmin.crossProfileWidgetProviders;
@@ -3062,7 +3069,7 @@
             }
         }
 
-        int callingUid = binderGetCallingUid();
+        int callingUid = mInjector.binderGetCallingUid();
         DevicePolicyData policy = getUserData(userHandle);
         if (policy.mPasswordOwner >= 0 && policy.mPasswordOwner != callingUid) {
             Slog.w(LOG_TAG, "resetPassword: already set by another uid and not entered by user");
@@ -3078,7 +3085,7 @@
 
         // Don't do this with the lock held, because it is going to call
         // back in to the service.
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             LockPatternUtils utils = new LockPatternUtils(mContext);
             if (!TextUtils.isEmpty(password)) {
@@ -3099,7 +3106,7 @@
                 }
             }
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
 
         return true;
@@ -3149,7 +3156,7 @@
             return;
         }
 
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             if (timeMs <= 0) {
                 timeMs = Integer.MAX_VALUE;
@@ -3161,9 +3168,11 @@
             }
 
             policy.mLastMaximumTimeToLock = timeMs;
-            mPowerManagerInternal.setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
+            // TODO It can overflow.  Cap it.
+            mInjector.getPowerManagerInternal()
+                    .setMaximumScreenOffTimeoutFromDeviceAdmin((int)timeMs);
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -3215,26 +3224,21 @@
     }
 
     private void lockNowUnchecked() {
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             // Power off the display
-            powerManagerGoToSleep(SystemClock.uptimeMillis(),
+            mInjector.powerManagerGoToSleep(SystemClock.uptimeMillis(),
                     PowerManager.GO_TO_SLEEP_REASON_DEVICE_ADMIN, 0);
             // Ensure the device is locked
             new LockPatternUtils(mContext).requireStrongAuth(
                     STRONG_AUTH_REQUIRED_AFTER_DPM_LOCK_NOW, UserHandle.USER_ALL);
-            mIWindowManager.lockNow(null);
+            mInjector.getIWindowManager().lockNow(null);
         } catch (RemoteException e) {
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
-    private boolean isExtStorageEncrypted() {
-        String state = SystemProperties.get("vold.decrypt");
-        return !"".equals(state);
-    }
-
     @Override
     public void enforceCanManageCaCerts(ComponentName who) {
         if (who == null) {
@@ -3249,7 +3253,7 @@
     }
 
     private boolean isCallerDelegatedCertInstaller() {
-        final int callingUid = binderGetCallingUid();
+        final int callingUid = mInjector.binderGetCallingUid();
         final int userHandle = UserHandle.getUserId(callingUid);
         synchronized (this) {
             final DevicePolicyData policy = getUserData(userHandle);
@@ -3284,7 +3288,7 @@
         }
 
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
-        final long id = binderClearCallingIdentity();
+        final long id = mInjector.binderClearCallingIdentity();
         try {
             final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
             try {
@@ -3299,7 +3303,7 @@
             Log.w(LOG_TAG, "installCaCertsToKeyChain(): ", e1);
             Thread.currentThread().interrupt();
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
         return false;
     }
@@ -3315,7 +3319,7 @@
         enforceCanManageCaCerts(admin);
 
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
-        final long id = binderClearCallingIdentity();
+        final long id = mInjector.binderClearCallingIdentity();
         try {
             final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
             try {
@@ -3331,7 +3335,7 @@
             Log.w(LOG_TAG, "CaCertUninstaller: ", ie);
             Thread.currentThread().interrupt();
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
@@ -3347,7 +3351,7 @@
             }
         }
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
-        final long id = binderClearCallingIdentity();
+        final long id = mInjector.binderClearCallingIdentity();
         try {
           final KeyChainConnection keyChainConnection = KeyChain.bindAsUser(mContext, userHandle);
           try {
@@ -3362,7 +3366,7 @@
             Log.w(LOG_TAG, "Interrupted while installing certificate", e);
             Thread.currentThread().interrupt();
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
         return false;
     }
@@ -3371,11 +3375,11 @@
     public void choosePrivateKeyAlias(final int uid, final Uri uri, final String alias,
             final IBinder response) {
         // Caller UID needs to be trusted, so we restrict this method to SYSTEM_UID callers.
-        if (UserHandle.getAppId(binderGetCallingUid()) != Process.SYSTEM_UID) {
+        if (UserHandle.getAppId(mInjector.binderGetCallingUid()) != Process.SYSTEM_UID) {
             return;
         }
 
-        final UserHandle caller = binderGetCallingUserHandle();
+        final UserHandle caller = mInjector.binderGetCallingUserHandle();
         // If there is a profile owner, redirect to that; otherwise query the device owner.
         ComponentName aliasChooser = getProfileOwner(caller.getIdentifier());
         if (aliasChooser == null && caller.isOwner()) {
@@ -3396,7 +3400,7 @@
         intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_ALIAS, alias);
         intent.putExtra(DeviceAdminReceiver.EXTRA_CHOOSE_PRIVATE_KEY_RESPONSE, response);
 
-        final long id = binderClearCallingIdentity();
+        final long id = mInjector.binderClearCallingIdentity();
         try {
             mContext.sendOrderedBroadcastAsUser(intent, caller, null, new BroadcastReceiver() {
                 @Override
@@ -3406,7 +3410,7 @@
                 }
             }, null, Activity.RESULT_OK, null, null);
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
@@ -3477,7 +3481,7 @@
 
             final String source = admin.info.getComponent().flattenToShortString();
 
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
                 if ((flags & WIPE_RESET_PROTECTION_DATA) != 0) {
                     boolean ownsInitialization = isDeviceInitializer(admin.info.getPackageName())
@@ -3498,7 +3502,7 @@
                 wipeDeviceOrUserLocked(wipeExtRequested, userHandle,
                         "DevicePolicyManager.wipeData() from " + source);
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -3511,7 +3515,7 @@
                 @Override
                 public void run() {
                     try {
-                        IActivityManager am = getIActivityManager();
+                        IActivityManager am = mInjector.getIActivityManager();
                         if (am.getCurrentUser().id == userHandle) {
                             am.switchUser(UserHandle.USER_SYSTEM);
                         }
@@ -3539,11 +3543,11 @@
                 .setColor(mContext.getColor(R.color.system_notification_accent_color))
                 .setStyle(new Notification.BigTextStyle().bigText(contentText))
                 .build();
-        mNotificationManager.notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
+        mInjector.getNotificationManager().notify(PROFILE_WIPED_NOTIFICATION_ID, notification);
     }
 
     private void clearWipeProfileNotification() {
-        mNotificationManager.cancel(PROFILE_WIPED_NOTIFICATION_ID);
+        mInjector.getNotificationManager().cancel(PROFILE_WIPED_NOTIFICATION_ID);
     }
 
     @Override
@@ -3603,7 +3607,7 @@
                     || p.mActivePasswordNumeric != numbers
                     || p.mActivePasswordSymbols != symbols
                     || p.mActivePasswordNonLetter != nonletter) {
-                long ident = binderClearCallingIdentity();
+                long ident = mInjector.binderClearCallingIdentity();
                 try {
                     p.mActivePasswordQuality = quality;
                     p.mActivePasswordLength = length;
@@ -3621,7 +3625,7 @@
                             DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                             DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
                 } finally {
-                    binderRestoreCallingIdentity(ident);
+                    mInjector.binderRestoreCallingIdentity(ident);
                 }
             }
         }
@@ -3657,7 +3661,7 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.BIND_DEVICE_ADMIN, null);
 
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             boolean wipeData = false;
             int identifier = 0;
@@ -3688,7 +3692,7 @@
                         "reportFailedPasswordAttempt()");
             }
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -3701,7 +3705,7 @@
         synchronized (this) {
             DevicePolicyData policy = getUserData(userHandle);
             if (policy.mFailedPasswordAttempts != 0 || policy.mPasswordOwner >= 0) {
-                long ident = binderClearCallingIdentity();
+                long ident = mInjector.binderClearCallingIdentity();
                 try {
                     policy.mFailedPasswordAttempts = 0;
                     policy.mPasswordOwner = -1;
@@ -3712,7 +3716,7 @@
                                 DeviceAdminInfo.USES_POLICY_WATCH_LOGIN, userHandle);
                     }
                 } finally {
-                    binderRestoreCallingIdentity(ident);
+                    mInjector.binderRestoreCallingIdentity(ident);
                 }
             }
         }
@@ -3763,11 +3767,11 @@
 
             // Reset the global proxy accordingly
             // Do this using system permissions, as apps cannot write to secure settings
-            long origId = binderClearCallingIdentity();
+            long origId = mInjector.binderClearCallingIdentity();
             try {
                 resetGlobalProxyLocked(policy);
             } finally {
-                binderRestoreCallingIdentity(origId);
+                mInjector.binderRestoreCallingIdentity(origId);
             }
             return null;
         }
@@ -3802,13 +3806,13 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
         }
-        long token = binderClearCallingIdentity();
+        long token = mInjector.binderClearCallingIdentity();
         try {
             ConnectivityManager connectivityManager = (ConnectivityManager)
                     mContext.getSystemService(Context.CONNECTIVITY_SERVICE);
             connectivityManager.setGlobalProxy(proxyInfo);
         } finally {
-            binderRestoreCallingIdentity(token);
+            mInjector.binderRestoreCallingIdentity(token);
         }
     }
 
@@ -3969,15 +3973,15 @@
      * {@link DevicePolicyManager#ENCRYPTION_STATUS_ACTIVE}.
      */
     private int getEncryptionStatus() {
-        String status = SystemProperties.get("ro.crypto.state", "unsupported");
+        String status = mInjector.systemPropertiesGet("ro.crypto.state", "unsupported");
         if ("encrypted".equalsIgnoreCase(status)) {
-            final long token = binderClearCallingIdentity();
+            final long token = mInjector.binderClearCallingIdentity();
             try {
                 return LockPatternUtils.isDeviceEncrypted()
                         ? DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE
                         : DevicePolicyManager.ENCRYPTION_STATUS_ACTIVE_DEFAULT_KEY;
             } finally {
-                binderRestoreCallingIdentity(token);
+                mInjector.binderRestoreCallingIdentity(token);
             }
         } else if ("unencrypted".equalsIgnoreCase(status)) {
             return DevicePolicyManager.ENCRYPTION_STATUS_INACTIVE;
@@ -4042,13 +4046,13 @@
     }
 
     private void updateScreenCaptureDisabledInWindowManager(int userHandle, boolean disabled) {
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
-            mIWindowManager.setScreenCaptureDisabled(userHandle, disabled);
+            mInjector.getIWindowManager().setScreenCaptureDisabled(userHandle, disabled);
         } catch (RemoteException e) {
             Log.w(LOG_TAG, "Unable to notify WindowManager.", e);
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -4073,12 +4077,12 @@
 
         // Turn AUTO_TIME on in settings if it is required
         if (required) {
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
                 Settings.Global.putInt(mContext.getContentResolver(),
                         Settings.Global.AUTO_TIME, 1 /* AUTO_TIME on */);
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -4187,7 +4191,7 @@
             return 0;
         }
         enforceCrossUserPermission(userHandle);
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             synchronized (this) {
                 if (who != null) {
@@ -4230,7 +4234,7 @@
                 return which;
             }
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -4240,7 +4244,7 @@
             return false;
         }
         if (packageName == null
-                || !Owners.isInstalledForUser(packageName, userId)) {
+                || !isPackageInstalledForUser(packageName, userId)) {
             throw new IllegalArgumentException("Invalid package name " + packageName
                     + " for device owner");
         }
@@ -4248,15 +4252,13 @@
             enforceCanSetDeviceOwner(userId);
 
             // Shutting down backup manager service permanently.
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
-                IBackupManager ibm = IBackupManager.Stub.asInterface(
-                        ServiceManager.getService(Context.BACKUP_SERVICE));
-                ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, false);
+                mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, false);
             } catch (RemoteException e) {
                 throw new IllegalStateException("Failed deactivating backup service.", e);
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
 
             mOwners.setDeviceOwner(packageName, ownerName, userId);
@@ -4264,12 +4266,12 @@
             updateDeviceOwnerLocked();
             Intent intent = new Intent(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED);
 
-            ident = binderClearCallingIdentity();
+            ident = mInjector.binderClearCallingIdentity();
             try {
                 // TODO Send to system too?
                 mContext.sendBroadcastAsUser(intent, new UserHandle(userId));
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
             return true;
         }
@@ -4301,11 +4303,14 @@
         if (!mHasFeature) {
             return null;
         }
+        // TODO: Do we really need it?  getDeviceOwner() doesn't require it.
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.MANAGE_USERS, null);
         synchronized (this) {
             if (!mOwners.hasDeviceOwner()) {
                 return null;
             }
+            // TODO This totally ignores the name passed to setDeviceOwner (change for b/20679292)
+            // Should setDeviceOwner/ProfileOwner still take a name?
             String deviceOwnerPackage = mOwners.getDeviceOwnerPackageName();
             return getApplicationLabel(deviceOwnerPackage, UserHandle.USER_SYSTEM);
         }
@@ -4334,7 +4339,7 @@
         Preconditions.checkNotNull(packageName, "packageName is null");
         try {
             int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
-            if (uid != binderGetCallingUid()) {
+            if (uid != mInjector.binderGetCallingUid()) {
                 throw new SecurityException("Invalid packageName");
             }
         } catch (NameNotFoundException e) {
@@ -4350,15 +4355,13 @@
             mOwners.writeDeviceOwner();
             updateDeviceOwnerLocked();
             // Reactivate backup service.
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
-                IBackupManager ibm = IBackupManager.Stub.asInterface(
-                        ServiceManager.getService(Context.BACKUP_SERVICE));
-                ibm.setBackupServiceActive(UserHandle.USER_SYSTEM, true);
+                mInjector.getIBackupManager().setBackupServiceActive(UserHandle.USER_SYSTEM, true);
             } catch (RemoteException e) {
                 throw new IllegalStateException("Failed reactivating backup service.", e);
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -4370,15 +4373,16 @@
         }
         if (initializer == null ||
                 !mOwners.hasDeviceOwner() ||
-                !Owners.isInstalledForUser(initializer.getPackageName(),
+                !isPackageInstalledForUser(initializer.getPackageName(),
                         mOwners.getDeviceOwnerUserId())) {
             throw new IllegalArgumentException("Invalid component name " + initializer
                     + " for device initializer or no device owner set");
         }
         boolean isInitializerSystemApp;
         try {
-            isInitializerSystemApp = isSystemApp(AppGlobals.getPackageManager(),
-                    initializer.getPackageName(), binderGetCallingUserHandle().getIdentifier());
+            isInitializerSystemApp = isSystemApp(mIPackageManager,
+                    initializer.getPackageName(),
+                    mInjector.binderGetCallingUserHandle().getIdentifier());
         } catch (RemoteException | IllegalArgumentException e) {
             isInitializerSystemApp = false;
             Slog.e(LOG_TAG, "Fail to check if device initialzer is system app.", e);
@@ -4461,9 +4465,9 @@
 
         ActiveAdmin admin = getActiveAdminUncheckedLocked(who, UserHandle.getCallingUserId());
 
-        if (admin.getUid() != binderGetCallingUid()) {
+        if (admin.getUid() != mInjector.binderGetCallingUid()) {
             throw new SecurityException("Admin " + who + " is not owned by uid "
-                    + binderGetCallingUid());
+                    + mInjector.binderGetCallingUid());
         }
 
         if (!isDeviceInitializer(admin.info.getPackageName())
@@ -4472,12 +4476,12 @@
                     "clearDeviceInitializer can only be called by the device initializer/owner");
         }
         synchronized (this) {
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
                 mOwners.clearDeviceInitializer();
                 mOwners.writeDeviceOwner();
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -4488,7 +4492,7 @@
             return false;
         }
         if (who == null
-                || !Owners.isInstalledForUser(who.getPackageName(), userHandle)) {
+                || !isPackageInstalledForUser(who.getPackageName(), userHandle)) {
             throw new IllegalArgumentException("Component " + who
                     + " not installed for userId:" + userHandle);
         }
@@ -4505,7 +4509,7 @@
         if (!mHasFeature) {
             return;
         }
-        UserHandle callingUser = binderGetCallingUserHandle();
+        UserHandle callingUser = mInjector.binderGetCallingUserHandle();
         // Check if this is the profile owner who is calling
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         synchronized (this) {
@@ -4525,15 +4529,15 @@
         policy.mStatusBarDisabled = false;
         saveSettingsLocked(userId);
 
-        final long ident = binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
             clearUserRestrictions(userHandle);
-            AppGlobals.getPackageManager().updatePermissionFlagsForAllApps(
+            mIPackageManager.updatePermissionFlagsForAllApps(
                     PackageManager.FLAG_PERMISSION_POLICY_FIXED,
                     0  /* flagValues */, userHandle.getIdentifier());
         } catch (RemoteException re) {
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -4541,11 +4545,9 @@
     private void clearUserRestrictions(UserHandle userHandle) {
         Bundle userRestrictions = mUserManager.getUserRestrictions();
         mUserManager.setUserRestrictions(new Bundle(), userHandle);
-        IAudioService iAudioService = IAudioService.Stub.asInterface(
-                ServiceManager.getService(Context.AUDIO_SERVICE));
         if (userRestrictions.getBoolean(UserManager.DISALLOW_ADJUST_VOLUME)) {
             try {
-                iAudioService.setMasterMute(true, 0, mContext.getPackageName(),
+                mInjector.getIAudioService().setMasterMute(true, 0, mContext.getPackageName(),
                         userHandle.getIdentifier());
             } catch (RemoteException e) {
                 // Not much we can do here.
@@ -4553,7 +4555,7 @@
         }
         if (userRestrictions.getBoolean(UserManager.DISALLOW_UNMUTE_MICROPHONE)) {
             try {
-                iAudioService.setMicrophoneMute(true, mContext.getPackageName(),
+                mInjector.getIAudioService().setMicrophoneMute(true, mContext.getPackageName(),
                         userHandle.getIdentifier());
             } catch (RemoteException e) {
                 // Not much we can do here.
@@ -4570,9 +4572,7 @@
         if (!mHasFeature) {
             return true;
         }
-        DevicePolicyData policy = getUserData(userHandle);
-        // If policy is null, return true, else check if the setup has completed.
-        return policy == null || policy.mUserSetupComplete;
+        return getUserData(userHandle).mUserSetupComplete;
     }
 
     @Override
@@ -4593,11 +4593,10 @@
                         "This method can only be called by device initializers");
             }
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 if (!isDeviceOwner(activeAdmin.info.getPackageName())) {
-                    IPackageManager ipm = AppGlobals.getPackageManager();
-                    ipm.setComponentEnabledSetting(who,
+                    mIPackageManager.setComponentEnabledSetting(who,
                             PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                             PackageManager.DONT_KILL_APP, userId);
 
@@ -4614,7 +4613,7 @@
                 Log.i(LOG_TAG, "Can't talk to package manager", e);
                 return false;
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
             return true;
         }
@@ -4632,7 +4631,7 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             int userId = UserHandle.getCallingUserId();
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 mUserManager.setUserEnabled(userId);
                 UserInfo parent = mUserManager.getProfileParent(userId);
@@ -4642,7 +4641,7 @@
                         Intent.FLAG_RECEIVER_FOREGROUND);
                 mContext.sendBroadcastAsUser(intent, new UserHandle(parent.id));
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -4654,11 +4653,11 @@
         // Check if this is the profile owner (includes device owner).
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-        long id = binderClearCallingIdentity();
+        long id = mInjector.binderClearCallingIdentity();
         try {
             mUserManager.setUserName(userId, profileName);
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
@@ -4708,7 +4707,7 @@
      * Canonical name for a given package.
      */
     private String getApplicationLabel(String packageName, int userHandle) {
-        long token = binderClearCallingIdentity();
+        long token = mInjector.binderClearCallingIdentity();
         try {
             final Context userContext;
             try {
@@ -4726,7 +4725,7 @@
             }
             return result != null ? result.toString() : null;
         } finally {
-            binderRestoreCallingIdentity(token);
+            mInjector.binderRestoreCallingIdentity(token);
         }
     }
 
@@ -4752,7 +4751,7 @@
             throw new IllegalStateException("Trying to set the profile owner, but profile owner "
                     + "is already set.");
         }
-        int callingUid = binderGetCallingUid();
+        int callingUid = mInjector.binderGetCallingUid();
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
             if (hasUserSetupCompleted(userHandle) &&
                     AccountManager.get(mContext).getAccountsAsUser(userHandle).length > 0) {
@@ -4785,13 +4784,13 @@
             throw new IllegalStateException("User not running: " + userId);
         }
 
-        int callingUid = binderGetCallingUid();
+        int callingUid = mInjector.binderGetCallingUid();
         if (callingUid == Process.SHELL_UID || callingUid == Process.ROOT_UID) {
             if (!hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
                 return;
             }
             // STOPSHIP Do proper check in split user mode
-            if (!UserManager.isSplitSystemUser()) {
+            if (!mInjector.userManagerIsSplitSystemUser()) {
                 if (mUserManager.getUserCount() > 1) {
                     throw new IllegalStateException(
                             "Not allowed to set the device owner because there "
@@ -4810,7 +4809,7 @@
         mContext.enforceCallingOrSelfPermission(
                 android.Manifest.permission.MANAGE_PROFILE_AND_DEVICE_OWNERS, null);
         // STOPSHIP Do proper check in split user mode
-        if (!UserManager.isSplitSystemUser()) {
+        if (!mInjector.userManagerIsSplitSystemUser()) {
             if (hasUserSetupCompleted(UserHandle.USER_SYSTEM)) {
                 throw new IllegalStateException("Cannot set the device owner if the device is "
                         + "already set-up");
@@ -4822,7 +4821,7 @@
         if (userHandle < 0) {
             throw new IllegalArgumentException("Invalid userId " + userHandle);
         }
-        final int callingUid = binderGetCallingUid();
+        final int callingUid = mInjector.binderGetCallingUid();
         if (userHandle == UserHandle.getUserId(callingUid)) return;
         if (callingUid != Process.SYSTEM_UID && callingUid != 0) {
             mContext.enforceCallingOrSelfPermission(
@@ -4838,32 +4837,31 @@
     }
 
     private UserInfo getProfileParent(int userHandle) {
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             return mUserManager.getProfileParent(userHandle);
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
     private boolean isManagedProfile(int userHandle) {
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             return mUserManager.getUserInfo(userHandle).isManagedProfile();
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
     private void enableIfNecessary(String packageName, int userId) {
         try {
-            IPackageManager ipm = AppGlobals.getPackageManager();
-            ApplicationInfo ai = ipm.getApplicationInfo(packageName,
+            ApplicationInfo ai = mIPackageManager.getApplicationInfo(packageName,
                     PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS,
                     userId);
             if (ai.enabledSetting
                     == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
-                ipm.setApplicationEnabledSetting(packageName,
+                mIPackageManager.setApplicationEnabledSetting(packageName,
                         PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
                         PackageManager.DONT_KILL_APP, userId, "DevicePolicyManager");
             }
@@ -4877,8 +4875,8 @@
                 != PackageManager.PERMISSION_GRANTED) {
 
             pw.println("Permission Denial: can't dump DevicePolicyManagerService from from pid="
-                    + binderGetCallingPid()
-                    + ", uid=" + binderGetCallingUid());
+                    + mInjector.binderGetCallingPid()
+                    + ", uid=" + mInjector.binderGetCallingUid());
             return;
         }
 
@@ -4919,14 +4917,13 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            IPackageManager pm = AppGlobals.getPackageManager();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
-                pm.addPersistentPreferredActivity(filter, activity, userHandle);
+                mIPackageManager.addPersistentPreferredActivity(filter, activity, userHandle);
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -4938,14 +4935,13 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            IPackageManager pm = AppGlobals.getPackageManager();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
-                pm.clearPackagePersistentPreferredActivities(packageName, userHandle);
+                mIPackageManager.clearPackagePersistentPreferredActivities(packageName, userHandle);
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -4957,11 +4953,11 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 mUserManager.setApplicationRestrictions(packageName, settings, userHandle);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5059,7 +5055,7 @@
     @Override
     public ComponentName getRestrictionsProvider(int userHandle) {
         synchronized (this) {
-            if (binderGetCallingUid() != Process.SYSTEM_UID) {
+            if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
                 throw new SecurityException("Only the system can query the permission provider");
             }
             DevicePolicyData userData = getUserData(userHandle);
@@ -5074,8 +5070,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            IPackageManager pm = AppGlobals.getPackageManager();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 UserInfo parent = mUserManager.getProfileParent(callingUserId);
                 if (parent == null) {
@@ -5084,17 +5079,17 @@
                     return;
                 }
                 if ((flags & DevicePolicyManager.FLAG_PARENT_CAN_ACCESS_MANAGED) != 0) {
-                    pm.addCrossProfileIntentFilter(filter, who.getPackageName(), callingUserId,
-                            parent.id, 0);
+                    mIPackageManager.addCrossProfileIntentFilter(
+                            filter, who.getPackageName(), callingUserId, parent.id, 0);
                 }
                 if ((flags & DevicePolicyManager.FLAG_MANAGED_CAN_ACCESS_PARENT) != 0) {
-                    pm.addCrossProfileIntentFilter(filter, who.getPackageName(),
+                    mIPackageManager.addCrossProfileIntentFilter(filter, who.getPackageName(),
                             parent.id, callingUserId, 0);
                 }
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5105,8 +5100,7 @@
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            IPackageManager pm = AppGlobals.getPackageManager();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 UserInfo parent = mUserManager.getProfileParent(callingUserId);
                 if (parent == null) {
@@ -5115,15 +5109,16 @@
                     return;
                 }
                 // Removing those that go from the managed profile to the parent.
-                pm.clearCrossProfileIntentFilters(callingUserId, who.getPackageName());
+                mIPackageManager.clearCrossProfileIntentFilters(
+                        callingUserId, who.getPackageName());
                 // And those that go from the parent to the managed profile.
                 // If we want to support multiple managed profiles, we will have to only remove
                 // those that have callingUserId as their target.
-                pm.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
+                mIPackageManager.clearCrossProfileIntentFilters(parent.id, who.getPackageName());
             } catch (RemoteException re) {
                 // Shouldn't happen
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5135,7 +5130,7 @@
     private boolean checkPackagesInPermittedListOrSystem(List<String> enabledPackages,
             List<String> permittedList) {
         int userIdToCheck = UserHandle.getCallingUserId();
-        long id = binderClearCallingIdentity();
+        long id = mInjector.binderClearCallingIdentity();
         try {
             // If we have an enabled packages list for a managed profile the packages
             // we should check are installed for the parent user.
@@ -5144,12 +5139,11 @@
                 userIdToCheck = user.profileGroupId;
             }
 
-            IPackageManager pm = AppGlobals.getPackageManager();
             for (String enabledPackage : enabledPackages) {
                 boolean systemService = false;
                 try {
-                    ApplicationInfo applicationInfo = pm.getApplicationInfo(enabledPackage,
-                            PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
+                    ApplicationInfo applicationInfo = mIPackageManager.getApplicationInfo(
+                            enabledPackage, PackageManager.GET_UNINSTALLED_PACKAGES, userIdToCheck);
                     systemService = (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
                 } catch (RemoteException e) {
                     Log.i(LOG_TAG, "Can't talk to package managed", e);
@@ -5159,7 +5153,7 @@
                 }
             }
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
         return true;
     }
@@ -5184,7 +5178,7 @@
         if (packageList != null) {
             int userId = UserHandle.getCallingUserId();
             List<AccessibilityServiceInfo> enabledServices = null;
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 UserInfo user = mUserManager.getUserInfo(userId);
                 if (user.isManagedProfile()) {
@@ -5194,7 +5188,7 @@
                 enabledServices = accessibilityManager.getEnabledAccessibilityServiceList(
                         AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
 
             if (enabledServices != null) {
@@ -5265,7 +5259,7 @@
 
             // If we have a permitted list add all system accessibility services.
             if (result != null) {
-                long id = binderClearCallingIdentity();
+                long id = mInjector.binderClearCallingIdentity();
                 try {
                     UserInfo user = mUserManager.getUserInfo(userId);
                     if (user.isManagedProfile()) {
@@ -5276,7 +5270,6 @@
                     List<AccessibilityServiceInfo> installedServices =
                             accessibilityManager.getInstalledAccessibilityServiceList();
 
-                    IPackageManager pm = AppGlobals.getPackageManager();
                     if (installedServices != null) {
                         for (AccessibilityServiceInfo service : installedServices) {
                             ServiceInfo serviceInfo = service.getResolveInfo().serviceInfo;
@@ -5287,7 +5280,7 @@
                         }
                     }
                 } finally {
-                    binderRestoreCallingIdentity(id);
+                    mInjector.binderRestoreCallingIdentity(id);
                 }
             }
 
@@ -5297,12 +5290,12 @@
 
     private boolean checkCallerIsCurrentUserOrProfile() {
         int callingUserId = UserHandle.getCallingUserId();
-        long token = binderClearCallingIdentity();
+        long token = mInjector.binderClearCallingIdentity();
         try {
             UserInfo currentUser;
             UserInfo callingUser = mUserManager.getUserInfo(callingUserId);
             try {
-                currentUser = getIActivityManager().getCurrentUser();
+                currentUser = mInjector.getIActivityManager().getCurrentUser();
             } catch (RemoteException e) {
                 Slog.e(LOG_TAG, "Failed to talk to activity managed.", e);
                 return false;
@@ -5319,7 +5312,7 @@
                 return false;
             }
         } finally {
-            binderRestoreCallingIdentity(token);
+            mInjector.binderRestoreCallingIdentity(token);
         }
         return true;
     }
@@ -5385,7 +5378,7 @@
     public List getPermittedInputMethodsForCurrentUser() {
         UserInfo currentUser;
         try {
-            currentUser = getIActivityManager().getCurrentUser();
+            currentUser = mInjector.getIActivityManager().getCurrentUser();
         } catch (RemoteException e) {
             Slog.e(LOG_TAG, "Failed to make remote calls to get current user", e);
             // Activity managed is dead, just allow all IMEs
@@ -5423,9 +5416,8 @@
                 InputMethodManager inputMethodManager = (InputMethodManager) mContext
                         .getSystemService(Context.INPUT_METHOD_SERVICE);
                 List<InputMethodInfo> imes = inputMethodManager.getInputMethodList();
-                long id = binderClearCallingIdentity();
+                long id = mInjector.binderClearCallingIdentity();
                 try {
-                    IPackageManager pm = AppGlobals.getPackageManager();
                     if (imes != null) {
                         for (InputMethodInfo ime : imes) {
                             ServiceInfo serviceInfo = ime.getServiceInfo();
@@ -5436,7 +5428,7 @@
                         }
                     }
                 } finally {
-                    binderRestoreCallingIdentity(id);
+                    mInjector.binderRestoreCallingIdentity(id);
                 }
             }
             return result;
@@ -5449,7 +5441,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 UserInfo userInfo = mUserManager.createUser(name, 0 /* flags */);
                 if (userInfo != null) {
@@ -5457,7 +5449,7 @@
                 }
                 return null;
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5469,21 +5461,19 @@
         if (user == null) {
             return null;
         }
-        long id = binderClearCallingIdentity();
+        long id = mInjector.binderClearCallingIdentity();
         try {
             String profileOwnerPkg = profileOwnerComponent.getPackageName();
-            final IPackageManager ipm = AppGlobals.getPackageManager();
-            IActivityManager activityManager = getIActivityManager();
 
             final int userHandle = user.getIdentifier();
             try {
                 // Install the profile owner if not present.
-                if (!ipm.isPackageAvailable(profileOwnerPkg, userHandle)) {
-                    ipm.installExistingPackageAsUser(profileOwnerPkg, userHandle);
+                if (!mIPackageManager.isPackageAvailable(profileOwnerPkg, userHandle)) {
+                    mIPackageManager.installExistingPackageAsUser(profileOwnerPkg, userHandle);
                 }
 
                 // Start user in background.
-                activityManager.startUserInBackground(userHandle);
+                mInjector.getIActivityManager().startUserInBackground(userHandle);
             } catch (RemoteException e) {
                 Slog.e(LOG_TAG, "Failed to make remote calls for configureUser", e);
             }
@@ -5492,7 +5482,7 @@
             setProfileOwner(profileOwnerComponent, ownerName, userHandle);
             return user;
         } finally {
-            binderRestoreCallingIdentity(id);
+            mInjector.binderRestoreCallingIdentity(id);
         }
     }
 
@@ -5502,11 +5492,11 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 return mUserManager.removeUser(userHandle.getIdentifier());
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5517,18 +5507,18 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 int userId = UserHandle.USER_SYSTEM;
                 if (userHandle != null) {
                     userId = userHandle.getIdentifier();
                 }
-                return getIActivityManager().switchUser(userId);
+                return mInjector.getIActivityManager().switchUser(userId);
             } catch (RemoteException e) {
                 Log.e(LOG_TAG, "Couldn't switch user", e);
                 return false;
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5541,14 +5531,14 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 Bundle bundle = mUserManager.getApplicationRestrictions(packageName, userHandle);
                 // if no restrictions were saved, mUserManager.getApplicationRestrictions
                 // returns null, but DPM method should return an empty Bundle as per JavaDoc
                 return bundle != null ? bundle : Bundle.EMPTY;
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5571,22 +5561,15 @@
             }
             boolean alreadyRestricted = mUserManager.hasUserRestriction(key, user);
 
-            IAudioService iAudioService = null;
-            if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)
-                    || UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                iAudioService = IAudioService.Stub.asInterface(
-                        ServiceManager.getService(Context.AUDIO_SERVICE));
-            }
-
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 if (enabled && !alreadyRestricted) {
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
-                        iAudioService.setMicrophoneMute(true, mContext.getPackageName(),
-                                userHandle);
+                        mInjector.getIAudioService()
+                                .setMicrophoneMute(true, mContext.getPackageName(), userHandle);
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.setMasterMute(true, 0, mContext.getPackageName(),
-                                userHandle);
+                        mInjector.getIAudioService()
+                                .setMasterMute(true, 0, mContext.getPackageName(), userHandle);
                     } else if (UserManager.DISALLOW_CONFIG_WIFI.equals(key)) {
                         Settings.Secure.putIntForUser(mContext.getContentResolver(),
                                 Settings.Secure.WIFI_NETWORKS_AVAILABLE_NOTIFICATION_ON, 0,
@@ -5624,8 +5607,8 @@
                         // Send out notifications however as some clients may want to reread the
                         // value which actually changed due to a restriction having been applied.
                         final String property = Settings.Secure.SYS_PROP_SETTING_VERSION;
-                        long version = SystemProperties.getLong(property, 0) + 1;
-                        SystemProperties.set(property, Long.toString(version));
+                        long version = mInjector.systemPropertiesGetLong(property, 0) + 1;
+                        mInjector.systemPropertiesSet(property, Long.toString(version));
 
                         final String name = Settings.Secure.LOCATION_PROVIDERS_ALLOWED;
                         Uri url = Uri.withAppendedPath(Settings.Secure.CONTENT_URI, name);
@@ -5634,17 +5617,17 @@
                 }
                 if (!enabled && alreadyRestricted) {
                     if (UserManager.DISALLOW_UNMUTE_MICROPHONE.equals(key)) {
-                        iAudioService.setMicrophoneMute(false, mContext.getPackageName(),
-                                userHandle);
+                        mInjector.getIAudioService()
+                                .setMicrophoneMute(false, mContext.getPackageName(), userHandle);
                     } else if (UserManager.DISALLOW_ADJUST_VOLUME.equals(key)) {
-                        iAudioService.setMasterMute(false, 0, mContext.getPackageName(),
-                                userHandle);
+                        mInjector.getIAudioService()
+                                .setMasterMute(false, 0, mContext.getPackageName(), userHandle);
                     }
                 }
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Failed to talk to AudioService.", re);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
             sendChangedNotification(userHandle);
         }
@@ -5658,15 +5641,15 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
-                return pm.setApplicationHiddenSettingAsUser(packageName, hidden, callingUserId);
+                return mIPackageManager.setApplicationHiddenSettingAsUser(
+                        packageName, hidden, callingUserId);
             } catch (RemoteException re) {
                 // shouldn't happen
                 Slog.e(LOG_TAG, "Failed to setApplicationHiddenSetting", re);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
             return false;
         }
@@ -5679,15 +5662,15 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
-                return pm.getApplicationHiddenSettingAsUser(packageName, callingUserId);
+                return mIPackageManager.getApplicationHiddenSettingAsUser(
+                        packageName, callingUserId);
             } catch (RemoteException re) {
                 // shouldn't happen
                 Slog.e(LOG_TAG, "Failed to getApplicationHiddenSettingAsUser", re);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
             return false;
         }
@@ -5702,7 +5685,7 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userId = UserHandle.getCallingUserId();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
 
             try {
                 if (DBG) {
@@ -5718,19 +5701,18 @@
                     primaryUser = um.getUserInfo(userId);
                 }
 
-                IPackageManager pm = AppGlobals.getPackageManager();
-                if (!isSystemApp(pm, packageName, primaryUser.id)) {
+                if (!isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
                     throw new IllegalArgumentException("Only system apps can be enabled this way.");
                 }
 
                 // Install the app.
-                pm.installExistingPackageAsUser(packageName, userId);
+                mIPackageManager.installExistingPackageAsUser(packageName, userId);
 
             } catch (RemoteException re) {
                 // shouldn't happen
                 Slog.wtf(LOG_TAG, "Failed to install " + packageName, re);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5744,7 +5726,7 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userId = UserHandle.getCallingUserId();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
 
             try {
                 UserManager um = UserManager.get(mContext);
@@ -5755,8 +5737,8 @@
                     primaryUser = um.getUserInfo(userId);
                 }
 
-                IPackageManager pm = AppGlobals.getPackageManager();
-                List<ResolveInfo> activitiesToEnable = pm.queryIntentActivities(intent,
+                List<ResolveInfo> activitiesToEnable = mIPackageManager.queryIntentActivities(
+                        intent,
                         intent.resolveTypeIfNeeded(mContext.getContentResolver()),
                         0, // no flags
                         primaryUser.id);
@@ -5767,9 +5749,9 @@
                     for (ResolveInfo info : activitiesToEnable) {
                         if (info.activityInfo != null) {
                             String packageName = info.activityInfo.packageName;
-                            if (isSystemApp(pm, packageName, primaryUser.id)) {
+                            if (isSystemApp(mIPackageManager, packageName, primaryUser.id)) {
                                 numberOfAppsInstalled++;
-                                pm.installExistingPackageAsUser(packageName, userId);
+                                mIPackageManager.installExistingPackageAsUser(packageName, userId);
                             } else {
                                 Slog.d(LOG_TAG, "Not enabling " + packageName + " since is not a"
                                         + " system app");
@@ -5783,7 +5765,7 @@
                 Slog.wtf(LOG_TAG, "Failed to resolve intent for: " + intent);
                 return 0;
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5849,15 +5831,14 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
-                pm.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
+                mIPackageManager.setBlockUninstallForUser(packageName, uninstallBlocked, userId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slog.e(LOG_TAG, "Failed to setBlockUninstallForUser", re);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -5874,15 +5855,14 @@
                 getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             }
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
-                IPackageManager pm = AppGlobals.getPackageManager();
-                return pm.getBlockUninstallForUser(packageName, userId);
+                return mIPackageManager.getBlockUninstallForUser(packageName, userId);
             } catch (RemoteException re) {
                 // Shouldn't happen.
                 Slog.e(LOG_TAG, "Failed to getBlockUninstallForUser", re);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
         return false;
@@ -5934,7 +5914,7 @@
                 actualLookupKey, actualContactId, originalIntent);
         final int callingUserId = UserHandle.getCallingUserId();
 
-        final long ident = binderClearCallingIdentity();
+        final long ident = mInjector.binderClearCallingIdentity();
         try {
             synchronized (this) {
                 final int managedUserId = getManagedUserId(callingUserId);
@@ -5952,7 +5932,7 @@
                         mContext, intent, new UserHandle(managedUserId));
             }
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
     }
 
@@ -6033,7 +6013,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
-            int userHandle = binderGetCallingUserHandle().getIdentifier();
+            int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
             setLockTaskPackagesLocked(userHandle, new ArrayList<>(Arrays.asList(packages)));
         }
     }
@@ -6055,7 +6035,7 @@
         Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
-            int userHandle = binderGetCallingUserHandle().getIdentifier();
+            int userHandle = mInjector.binderGetCallingUserHandle().getIdentifier();
             final List<String> packages = getLockTaskPackagesLocked(userHandle);
             return packages.toArray(new String[packages.size()]);
         }
@@ -6074,7 +6054,7 @@
     @Override
     public boolean isLockTaskPermitted(String pkg) {
         // Get current user's devicepolicy
-        int uid = binderGetCallingUid();
+        int uid = mInjector.binderGetCallingUid();
         int userHandle = UserHandle.getUserId(uid);
         DevicePolicyData policy = getUserData(userHandle);
         synchronized (this) {
@@ -6093,7 +6073,7 @@
 
     @Override
     public void notifyLockTaskModeChanged(boolean isEnabled, String pkg, int userHandle) {
-        if (binderGetCallingUid() != Process.SYSTEM_UID) {
+        if (mInjector.binderGetCallingUid() != Process.SYSTEM_UID) {
             throw new SecurityException("notifyLockTaskModeChanged can only be called by system");
         }
         synchronized (this) {
@@ -6144,11 +6124,11 @@
                 }
             }
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 Settings.Global.putString(contentResolver, setting, value);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -6173,11 +6153,11 @@
                         "Permission denial: Profile owners cannot update %1$s", setting));
             }
 
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 Settings.Secure.putStringForUser(contentResolver, setting, value, callingUserId);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -6188,7 +6168,7 @@
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             int userId = UserHandle.getCallingUserId();
-            long identity = binderClearCallingIdentity();
+            long identity = mInjector.binderClearCallingIdentity();
             try {
                 IAudioService iAudioService = IAudioService.Stub.asInterface(
                         ServiceManager.getService(Context.AUDIO_SERVICE));
@@ -6196,7 +6176,7 @@
             } catch (RemoteException re) {
                 Slog.e(LOG_TAG, "Failed to setMasterMute", re);
             } finally {
-                binderRestoreCallingIdentity(identity);
+                mInjector.binderRestoreCallingIdentity(identity);
             }
         }
     }
@@ -6220,11 +6200,11 @@
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userId = UserHandle.getCallingUserId();
-            long id = binderClearCallingIdentity();
+            long id = mInjector.binderClearCallingIdentity();
             try {
                 mUserManager.setUserIcon(userId, icon);
             } finally {
-                binderRestoreCallingIdentity(id);
+                mInjector.binderRestoreCallingIdentity(id);
             }
         }
     }
@@ -6238,7 +6218,7 @@
         final int userId = UserHandle.getCallingUserId();
         LockPatternUtils utils = new LockPatternUtils(mContext);
 
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             // disallow disabling the keyguard if a password is currently set
             if (disabled && utils.isSecure(userId)) {
@@ -6246,7 +6226,7 @@
             }
             utils.setLockScreenDisabled(disabled, userId);
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
         return true;
     }
@@ -6269,7 +6249,7 @@
     }
 
     private boolean setStatusBarDisabledInternal(boolean disabled, int userId) {
-        long ident = binderClearCallingIdentity();
+        long ident = mInjector.binderClearCallingIdentity();
         try {
             IStatusBarService statusBarService = IStatusBarService.Stub.asInterface(
                     ServiceManager.checkService(Context.STATUS_BAR_SERVICE));
@@ -6283,7 +6263,7 @@
         } catch (RemoteException e) {
             Slog.e(LOG_TAG, "Failed to disable the status bar", e);
         } finally {
-            binderRestoreCallingIdentity(ident);
+            mInjector.binderRestoreCallingIdentity(ident);
         }
         return false;
     }
@@ -6514,7 +6494,7 @@
                 Log.e(LOG_TAG, "Cannot find device owner package", e);
             }
             if (receivers != null) {
-                long ident = binderClearCallingIdentity();
+                long ident = mInjector.binderClearCallingIdentity();
                 try {
                     for (int i = 0; i < receivers.length; i++) {
                         if (permission.BIND_DEVICE_ADMIN.equals(receivers[i].permission)) {
@@ -6524,7 +6504,7 @@
                         }
                     }
                 } finally {
-                    binderRestoreCallingIdentity(ident);
+                    mInjector.binderRestoreCallingIdentity(ident);
                 }
             }
         }
@@ -6555,12 +6535,12 @@
     @Override
     public boolean setPermissionGrantState(ComponentName admin, String packageName,
             String permission, int grantState) throws RemoteException {
-        UserHandle user = binderGetCallingUserHandle();
+        UserHandle user = mInjector.binderGetCallingUserHandle();
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
-                final ApplicationInfo ai = AppGlobals.getPackageManager()
+                final ApplicationInfo ai = mIPackageManager
                         .getApplicationInfo(packageName, 0, user.getIdentifier());
                 final int targetSdkVersion = ai == null ? 0 : ai.targetSdkVersion;
                 if (targetSdkVersion < android.os.Build.VERSION_CODES.M) {
@@ -6592,7 +6572,7 @@
             } catch (SecurityException se) {
                 return false;
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
@@ -6602,12 +6582,12 @@
             String permission) throws RemoteException {
         PackageManager packageManager = mContext.getPackageManager();
 
-        UserHandle user = binderGetCallingUserHandle();
+        UserHandle user = mInjector.binderGetCallingUserHandle();
         synchronized (this) {
             getActiveAdminForCallerLocked(admin, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
-            long ident = binderClearCallingIdentity();
+            long ident = mInjector.binderClearCallingIdentity();
             try {
-                int granted = AppGlobals.getPackageManager().checkPermission(permission,
+                int granted = mIPackageManager.checkPermission(permission,
                         packageName, user.getIdentifier());
                 int permFlags = packageManager.getPermissionFlags(permission, packageName, user);
                 if ((permFlags & PackageManager.FLAG_PERMISSION_POLICY_FIXED)
@@ -6621,8 +6601,17 @@
                             : DevicePolicyManager.PERMISSION_GRANT_STATE_DENIED;
                 }
             } finally {
-                binderRestoreCallingIdentity(ident);
+                mInjector.binderRestoreCallingIdentity(ident);
             }
         }
     }
+
+    boolean isPackageInstalledForUser(String packageName, int userHandle) {
+        try {
+            PackageInfo pi = mIPackageManager.getPackageInfo(packageName, 0, userHandle);
+            return (pi != null) && (pi.applicationInfo.flags != 0);
+        } catch (RemoteException re) {
+            throw new RuntimeException("Package manager has died", re);
+        }
+    }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
index 87cf28f..370cf48 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/Owners.java
@@ -101,7 +101,7 @@
 
     public Owners(Context context) {
         mContext = context;
-        mUserManager = UserManager.get(mContext);
+        mUserManager = context.getSystemService(UserManager.class);
     }
 
     /**
@@ -230,20 +230,6 @@
         return mDeviceOwner != null;
     }
 
-    static boolean isInstalledForUser(String packageName, int userHandle) {
-        try {
-            PackageInfo pi = (AppGlobals.getPackageManager())
-                    .getPackageInfo(packageName, 0, userHandle);
-            if (pi != null && pi.applicationInfo.flags != 0) {
-                return true;
-            }
-        } catch (RemoteException re) {
-            throw new RuntimeException("Package manager has died", re);
-        }
-
-        return false;
-    }
-
     private boolean readLegacyOwnerFile(File file) {
         if (!file.exists()) {
             // Already migrated or the device has no owners.
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 93dc6cb..1ec1a46 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -867,6 +867,11 @@
 
             if (!disableNonCoreServices) {
                 mSystemServiceManager.startService(DockObserver.class);
+
+                if (context.getPackageManager().hasSystemFeature
+                        (PackageManager.FEATURE_WATCH)) {
+                    mSystemServiceManager.startService(ThermalObserver.class);
+                }
             }
 
             traceBeginAndSlog("StartWiredAccessoryManager");
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 9ee9cf4..e0d2ac1 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -244,8 +244,9 @@
     private PendingIntent createStateMachineCommandIntent(final String cmdName, final int cmd) {
         String action = DhcpClient.class.getName() + "." + mIfaceName + "." + cmdName;
 
-        Intent intent = new Intent(action, null)
-                .addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
+        Intent intent = new Intent(action, null).addFlags(
+                Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT |
+                Intent.FLAG_RECEIVER_FOREGROUND);
         // TODO: The intent's package covers the whole of the system server, so it's pretty generic.
         // Consider adding some sort of token as well.
         intent.setPackage(mContext.getPackageName());
diff --git a/core/java/android/net/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
similarity index 84%
rename from core/java/android/net/IpReachabilityMonitor.java
rename to services/net/java/android/net/ip/IpReachabilityMonitor.java
index 2283004c..982bae0 100644
--- a/core/java/android/net/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package android.net;
+package android.net.ip;
 
 import com.android.internal.annotations.GuardedBy;
 
@@ -60,6 +60,74 @@
  * Monitors on-link IP reachability and notifies callers whenever any on-link
  * addresses of interest appear to have become unresponsive.
  *
+ * This code does not concern itself with "why" a neighbour might have become
+ * unreachable. Instead, it primarily reacts to the kernel's notion of IP
+ * reachability for each of the neighbours we know to be critically important
+ * to normal network connectivity. As such, it is often "just the messenger":
+ * the neighbours about which it warns are already deemed by the kernel to have
+ * become unreachable.
+ *
+ *
+ * How it works:
+ *
+ *   1. The "on-link neighbours of interest" found in a given LinkProperties
+ *      instance are added to a "watch list" via #updateLinkProperties().
+ *      This usually means all default gateways and any on-link DNS servers.
+ *
+ *   2. We listen continuously for netlink neighbour messages (RTM_NEWNEIGH,
+ *      RTM_DELNEIGH), watching only for neighbours in the watch list.
+ *
+ *        - A neighbour going into NUD_REACHABLE, NUD_STALE, NUD_DELAY, and
+ *          even NUD_PROBE is perfectly normal; we merely record the new state.
+ *
+ *        - A neighbour's entry may be deleted (RTM_DELNEIGH), for example due
+ *          to garbage collection.  This is not necessarily of immediate
+ *          concern; we record the neighbour as moving to NUD_NONE.
+ *
+ *        - A neighbour transitioning to NUD_FAILED (for any reason) is
+ *          critically important and is handled as described below in #4.
+ *
+ *   3. All on-link neighbours in the watch list can be forcibly "probed" by
+ *      calling #probeAll(). This should be called whenever it is important to
+ *      verify that critical neighbours on the link are still reachable, e.g.
+ *      when roaming between BSSIDs.
+ *
+ *        - The kernel will send unicast ARP requests for IPv4 neighbours and
+ *          unicast NS packets for IPv6 neighbours.  The expected replies will
+ *          likely be unicast.
+ *
+ *        - The forced probing is done holding a wakelock. The kernel may,
+ *          however, initiate probing of a neighbor on its own, i.e. whenever
+ *          a neighbour has expired from NUD_DELAY.
+ *
+ *        - The kernel sends:
+ *
+ *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/ucast_solicit
+ *
+ *          number of probes (usually 3) every:
+ *
+ *              /proc/sys/net/ipv{4,6}/neigh/<ifname>/retrans_time_ms
+ *
+ *          number of milliseconds (usually 1000ms). This normally results in
+ *          3 unicast packets, 1 per second.
+ *
+ *        - If no response is received to any of the probe packets, the kernel
+ *          marks the neighbour as being in state NUD_FAILED, and the listening
+ *          process in #2 will learn of it.
+ *
+ *   4. We call the supplied Callback#notifyLost() function if the loss of a
+ *      neighbour in NUD_FAILED would cause IPv4 or IPv6 configuration to
+ *      become incomplete (a loss of provisioning).
+ *
+ *        - For example, losing all our IPv4 on-link DNS servers (or losing
+ *          our only IPv6 default gateway) constitutes a loss of IPv4 (IPv6)
+ *          provisioning; Callback#notifyLost() would be called.
+ *
+ *        - Since it can be non-trivial to reacquire certain IP provisioning
+ *          state it may be best for the link to disconnect completely and
+ *          reconnect afresh.
+ *
+ *
  * @hide
  */
 public class IpReachabilityMonitor {
diff --git a/core/java/android/net/netlink/NetlinkConstants.java b/services/net/java/android/net/netlink/NetlinkConstants.java
similarity index 100%
rename from core/java/android/net/netlink/NetlinkConstants.java
rename to services/net/java/android/net/netlink/NetlinkConstants.java
diff --git a/core/java/android/net/netlink/NetlinkErrorMessage.java b/services/net/java/android/net/netlink/NetlinkErrorMessage.java
similarity index 100%
rename from core/java/android/net/netlink/NetlinkErrorMessage.java
rename to services/net/java/android/net/netlink/NetlinkErrorMessage.java
diff --git a/core/java/android/net/netlink/NetlinkMessage.java b/services/net/java/android/net/netlink/NetlinkMessage.java
similarity index 100%
rename from core/java/android/net/netlink/NetlinkMessage.java
rename to services/net/java/android/net/netlink/NetlinkMessage.java
diff --git a/core/java/android/net/netlink/NetlinkSocket.java b/services/net/java/android/net/netlink/NetlinkSocket.java
similarity index 100%
rename from core/java/android/net/netlink/NetlinkSocket.java
rename to services/net/java/android/net/netlink/NetlinkSocket.java
diff --git a/core/java/android/net/netlink/RtNetlinkNeighborMessage.java b/services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
similarity index 100%
rename from core/java/android/net/netlink/RtNetlinkNeighborMessage.java
rename to services/net/java/android/net/netlink/RtNetlinkNeighborMessage.java
diff --git a/core/java/android/net/netlink/StructNdMsg.java b/services/net/java/android/net/netlink/StructNdMsg.java
similarity index 100%
rename from core/java/android/net/netlink/StructNdMsg.java
rename to services/net/java/android/net/netlink/StructNdMsg.java
diff --git a/core/java/android/net/netlink/StructNdaCacheInfo.java b/services/net/java/android/net/netlink/StructNdaCacheInfo.java
similarity index 100%
rename from core/java/android/net/netlink/StructNdaCacheInfo.java
rename to services/net/java/android/net/netlink/StructNdaCacheInfo.java
diff --git a/core/java/android/net/netlink/StructNlAttr.java b/services/net/java/android/net/netlink/StructNlAttr.java
similarity index 100%
rename from core/java/android/net/netlink/StructNlAttr.java
rename to services/net/java/android/net/netlink/StructNlAttr.java
diff --git a/core/java/android/net/netlink/StructNlMsgErr.java b/services/net/java/android/net/netlink/StructNlMsgErr.java
similarity index 100%
rename from core/java/android/net/netlink/StructNlMsgErr.java
rename to services/net/java/android/net/netlink/StructNlMsgErr.java
diff --git a/core/java/android/net/netlink/StructNlMsgHdr.java b/services/net/java/android/net/netlink/StructNlMsgHdr.java
similarity index 100%
rename from core/java/android/net/netlink/StructNlMsgHdr.java
rename to services/net/java/android/net/netlink/StructNlMsgHdr.java
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index cb2c9b7..c147bcc 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -67,8 +67,26 @@
             </intent-filter>
         </receiver>
 
-        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmin"
-                android:permission="android.permission.BIND_DEVICE_ADMIN">
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin1"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_sample" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin2"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
+            <meta-data android:name="android.app.device_admin"
+                android:resource="@xml/device_admin_sample" />
+            <intent-filter>
+                <action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
+            </intent-filter>
+        </receiver>
+
+        <receiver android:name="com.android.server.devicepolicy.DummyDeviceAdmins$Admin3"
+            android:permission="android.permission.BIND_DEVICE_ADMIN">
             <meta-data android:name="android.app.device_admin"
                 android:resource="@xml/device_admin_sample" />
             <intent-filter>
diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
similarity index 100%
rename from core/tests/coretests/src/android/net/netlink/NetlinkErrorMessageTest.java
rename to services/tests/servicestests/src/android/net/netlink/NetlinkErrorMessageTest.java
diff --git a/core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java b/services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
similarity index 100%
rename from core/tests/coretests/src/android/net/netlink/NetlinkSocketTest.java
rename to services/tests/servicestests/src/android/net/netlink/NetlinkSocketTest.java
diff --git a/core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java b/services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
similarity index 100%
rename from core/tests/coretests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
rename to services/tests/servicestests/src/android/net/netlink/RtNetlinkNeighborMessageTest.java
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
deleted file mode 100644
index ca270e7..0000000
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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.server.devicepolicy;
-
-import android.app.admin.DeviceAdminReceiver;
-import android.app.admin.DevicePolicyManager;
-import android.content.BroadcastReceiver;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.os.Bundle;
-import android.os.UserHandle;
-import android.provider.Settings;
-import android.test.AndroidTestCase;
-import android.test.suitebuilder.annotation.SmallTest;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-
-/**
- * Tests for application restrictions persisting via profile owner:
- *   make -j FrameworksServicesTests
- *   runtest --path frameworks/base/services/tests/servicestests/ \
- *       src/com/android/server/devicepolicy/ApplicationRestrictionsTest.java
- */
-public class ApplicationRestrictionsTest extends AndroidTestCase {
-
-    static DevicePolicyManager sDpm;
-    static ComponentName sAdminReceiver;
-    private static final String RESTRICTED_APP = "com.example.restrictedApp";
-    static boolean sAddBack = false;
-
-    public static class AdminReceiver extends DeviceAdminReceiver {
-
-        @Override
-        public void onDisabled(Context context, Intent intent) {
-            if (sAddBack) {
-                sDpm.setActiveAdmin(sAdminReceiver, false);
-                sAddBack = false;
-            }
-
-            super.onDisabled(context, intent);
-        }
-    }
-
-    @Override
-    public void setUp() {
-        final Context context = getContext();
-        sAdminReceiver = new ComponentName(mContext.getPackageName(),
-                AdminReceiver.class.getName());
-        sDpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE);
-        Settings.Secure.putInt(context.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 0);
-        sDpm.setProfileOwner(sAdminReceiver, "Test", UserHandle.myUserId());
-        Settings.Secure.putInt(context.getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 1);
-        // Remove the admin if already registered. It's async, so add it back
-        // when the admin gets a broadcast. Otherwise add it back right away.
-        if (sDpm.isAdminActive(sAdminReceiver)) {
-            sAddBack = true;
-            sDpm.removeActiveAdmin(sAdminReceiver);
-        } else {
-            sDpm.setActiveAdmin(sAdminReceiver, false);
-        }
-    }
-
-    @Override
-    public void tearDown() {
-        Settings.Secure.putInt(getContext().getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 0);
-        sDpm.removeActiveAdmin(sAdminReceiver);
-        Settings.Secure.putInt(getContext().getContentResolver(),
-                Settings.Secure.USER_SETUP_COMPLETE, 1);
-    }
-
-    public void testSettingRestrictions() {
-        Bundle restrictions = new Bundle();
-        restrictions.putString("KEY_STRING", "Foo");
-        assertNotNull(sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP));
-        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
-        Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
-        assertNotNull(returned);
-        assertEquals(returned.size(), 1);
-        assertEquals(returned.get("KEY_STRING"), "Foo");
-        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
-        returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
-        assertEquals(returned.size(), 0);
-    }
-
-    public void testRestrictionTypes() {
-        Bundle restrictions = new Bundle();
-        restrictions.putString("KEY_STRING", "Foo");
-        restrictions.putInt("KEY_INT", 7);
-        restrictions.putBoolean("KEY_BOOLEAN", true);
-        restrictions.putBoolean("KEY_BOOLEAN_2", false);
-        restrictions.putString("KEY_STRING_2", "Bar");
-        restrictions.putStringArray("KEY_STR_ARRAY", new String[] { "Foo", "Bar" });
-        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
-        Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
-        assertTrue(returned.getBoolean("KEY_BOOLEAN"));
-        assertFalse(returned.getBoolean("KEY_BOOLEAN_2"));
-        assertFalse(returned.getBoolean("KEY_BOOLEAN_3"));
-        assertEquals(returned.getInt("KEY_INT"), 7);
-        assertTrue(returned.get("KEY_BOOLEAN") instanceof Boolean);
-        assertTrue(returned.get("KEY_INT") instanceof Integer);
-        assertEquals(returned.get("KEY_STRING"), "Foo");
-        assertEquals(returned.get("KEY_STRING_2"), "Bar");
-        assertTrue(returned.getStringArray("KEY_STR_ARRAY") instanceof String[]);
-        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, new Bundle());
-    }
-
-    public void testTextEscaping() {
-        String fancyText = "<This contains XML/> <JSON> "
-                + "{ \"One\": { \"OneOne\": \"11\", \"OneTwo\": \"12\" }, \"Two\": \"2\" } <JSON/>";
-        Bundle restrictions = new Bundle();
-        restrictions.putString("KEY_FANCY_TEXT", fancyText);
-        sDpm.setApplicationRestrictions(sAdminReceiver, RESTRICTED_APP, restrictions);
-        Bundle returned = sDpm.getApplicationRestrictions(sAdminReceiver, RESTRICTED_APP);
-        assertEquals(returned.getString("KEY_FANCY_TEXT"), fancyText);
-    }
-}
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
index cb439eb..c6c7497 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerServiceTestable.java
@@ -19,10 +19,11 @@
 
 import android.app.IActivityManager;
 import android.app.NotificationManager;
+import android.app.backup.IBackupManager;
 import android.content.Context;
-import android.content.pm.PackageManager;
+import android.content.pm.IPackageManager;
+import android.media.IAudioService;
 import android.os.Looper;
-import android.os.PowerManager.WakeLock;
 import android.os.PowerManagerInternal;
 import android.os.UserHandle;
 import android.os.UserManager;
@@ -45,9 +46,9 @@
         public static final String DEVICE_OWNER_FILE = "device_owner2.xml";
         public static final String PROFILE_OWNER_FILE_BASE = "profile_owner.xml";
 
-        final private File mLegacyFile;
-        final private File mDeviceOwnerFile;
-        final private File mProfileOwnerBase;
+        private final File mLegacyFile;
+        private final File mDeviceOwnerFile;
+        private final File mProfileOwnerBase;
 
         public OwnersTestable(Context context, File dataDir) {
             super(context);
@@ -72,121 +73,169 @@
         }
     }
 
-    public final File dataDir;
-    public final File systemUserDataDir;
-    public final File secondUserDataDir;
+    public final DpmMockContext context;
 
     public DevicePolicyManagerServiceTestable(DpmMockContext context, File dataDir) {
-        super(context);
-        this.dataDir = dataDir;
-
-        systemUserDataDir = new File(dataDir, "user0");
-        DpmTestUtils.clearDir(dataDir);
-
-        secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE);
-        DpmTestUtils.clearDir(secondUserDataDir);
-
-        when(getContext().environment.getUserSystemDirectory(
-                eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir);
+        this(new MockInjector(context, dataDir));
     }
 
-    @Override
-    DpmMockContext getContext() {
-        return (DpmMockContext) super.getContext();
+    private DevicePolicyManagerServiceTestable(MockInjector injector) {
+        super(injector);
+        this.context = injector.context;
     }
 
-    @Override
-    protected Owners newOwners() {
-        return new OwnersTestable(getContext(), dataDir);
-    }
+    private static class MockInjector extends Injector {
 
-    @Override
-    protected UserManager getUserManager() {
-        return getContext().userManager;
-    }
+        public final DpmMockContext context;
 
-    @Override
-    protected PackageManager getPackageManager() {
-        return getContext().packageManager;
-    }
+        public final File dataDir;
 
-    @Override
-    protected PowerManagerInternal getPowerManagerInternal() {
-        return getContext().powerManagerInternal;
-    }
+        public final File systemUserDataDir;
+        public final File secondUserDataDir;
 
-    @Override
-    protected NotificationManager getNotificationManager() {
-        return getContext().notificationManager;
-    }
+        private MockInjector(DpmMockContext context, File dataDir) {
+            super(context);
+            this.context = context;
+            this.dataDir = dataDir;
 
-    @Override
-    protected IWindowManager newIWindowManager() {
-        return getContext().iwindowManager;
-    }
+            systemUserDataDir = new File(dataDir, "user0");
+            DpmTestUtils.clearDir(dataDir);
 
-    @Override
-    protected IActivityManager getIActivityManager() {
-        return getContext().iactivityManager;
-    }
+            secondUserDataDir = new File(dataDir, "user" + DpmMockContext.CALLER_USER_HANDLE);
+            DpmTestUtils.clearDir(secondUserDataDir);
 
-    @Override
-    protected LockPatternUtils newLockPatternUtils(Context context) {
-        return getContext().lockPatternUtils;
-    }
+            when(context.environment.getUserSystemDirectory(
+                    eq(DpmMockContext.CALLER_USER_HANDLE))).thenReturn(secondUserDataDir);
+        }
 
-    @Override
-    protected Looper getMyLooper() {
-        return Looper.getMainLooper();
-    }
+        @Override
+        Owners newOwners() {
+            return new OwnersTestable(context, dataDir);
+        }
 
-    @Override
-    String getDevicePolicyFilePathForSystemUser() {
-        return systemUserDataDir.getAbsolutePath();
-    }
+        @Override
+        UserManager getUserManager() {
+            return context.userManager;
+        }
 
-    @Override
-    long binderClearCallingIdentity() {
-        return getContext().binder.clearCallingIdentity();
-    }
+        @Override
+        PowerManagerInternal getPowerManagerInternal() {
+            return context.powerManagerInternal;
+        }
 
-    @Override
-    void binderRestoreCallingIdentity(long token) {
-        getContext().binder.restoreCallingIdentity(token);
-    }
+        @Override
+        NotificationManager getNotificationManager() {
+            return context.notificationManager;
+        }
 
-    @Override
-    int binderGetCallingUid() {
-        return getContext().binder.getCallingUid();
-    }
+        @Override
+        IWindowManager getIWindowManager() {
+            return context.iwindowManager;
+        }
 
-    @Override
-    int binderGetCallingPid() {
-        return getContext().binder.getCallingPid();
-    }
+        @Override
+        IActivityManager getIActivityManager() {
+            return context.iactivityManager;
+        }
 
-    @Override
-    UserHandle binderGetCallingUserHandle() {
-        return getContext().binder.getCallingUserHandle();
-    }
+        @Override
+        IPackageManager getIPackageManager() {
+            return context.ipackageManager;
+        }
 
-    @Override
-    boolean binderIsCallingUidMyUid() {
-        return getContext().binder.isCallerUidMyUid();
-    }
+        @Override
+        IBackupManager getIBackupManager() {
+            return context.ibackupManager;
+        }
 
-    @Override
-    File environmentGetUserSystemDirectory(int userId) {
-        return getContext().environment.getUserSystemDirectory(userId);
-    }
+        @Override
+        IAudioService getIAudioService() {
+            return context.iaudioService;
+        }
 
-    @Override
-    WakeLock powerManagerNewWakeLock(int levelAndFlags, String tag) {
-        return getContext().powerManager.newWakeLock(levelAndFlags, tag);
-    }
+        @Override
+        Looper getMyLooper() {
+            return Looper.getMainLooper();
+        }
 
-    @Override
-    void powerManagerGoToSleep(long time, int reason, int flags) {
-        getContext().powerManager.goToSleep(time, reason, flags);
+        @Override
+        LockPatternUtils newLockPatternUtils() {
+            return context.lockPatternUtils;
+        }
+
+        @Override
+        String getDevicePolicyFilePathForSystemUser() {
+            return systemUserDataDir.getAbsolutePath();
+        }
+
+        @Override
+        long binderClearCallingIdentity() {
+            return context.binder.clearCallingIdentity();
+        }
+
+        @Override
+        void binderRestoreCallingIdentity(long token) {
+            context.binder.restoreCallingIdentity(token);
+        }
+
+        @Override
+        int binderGetCallingUid() {
+            return context.binder.getCallingUid();
+        }
+
+        @Override
+        int binderGetCallingPid() {
+            return context.binder.getCallingPid();
+        }
+
+        @Override
+        UserHandle binderGetCallingUserHandle() {
+            return context.binder.getCallingUserHandle();
+        }
+
+        @Override
+        boolean binderIsCallingUidMyUid() {
+            return context.binder.isCallerUidMyUid();
+        }
+
+        @Override
+        File environmentGetUserSystemDirectory(int userId) {
+            return context.environment.getUserSystemDirectory(userId);
+        }
+
+        @Override
+        void powerManagerGoToSleep(long time, int reason, int flags) {
+            context.powerManager.goToSleep(time, reason, flags);
+        }
+
+        @Override
+        boolean systemPropertiesGetBoolean(String key, boolean def) {
+            return context.systemProperties.getBoolean(key, def);
+        }
+
+        @Override
+        long systemPropertiesGetLong(String key, long def) {
+            return context.systemProperties.getLong(key, def);
+        }
+
+        @Override
+        String systemPropertiesGet(String key, String def) {
+            return context.systemProperties.get(key, def);
+        }
+
+        @Override
+        String systemPropertiesGet(String key) {
+            return context.systemProperties.get(key);
+        }
+
+        @Override
+        void systemPropertiesSet(String key, String value) {
+            context.systemProperties.set(key, value);
+        }
+
+        @Override
+        boolean userManagerIsSplitSystemUser() {
+            return context.userManagerForMock.isSplitSystemUser();
+        }
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 7cce56c..0072f52 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -13,33 +13,48 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-
 package com.android.server.devicepolicy;
 
 import com.android.server.LocalServices;
 
+import android.Manifest.permission;
+import android.app.Activity;
 import android.app.admin.DeviceAdminReceiver;
 import android.app.admin.DevicePolicyManager;
 import android.app.admin.DevicePolicyManagerInternal;
+import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
+import android.os.Bundle;
+import android.content.pm.PackageInfo;
+import android.content.pm.UserInfo;
 import android.os.UserHandle;
+import android.util.Pair;
 
 import org.mockito.ArgumentCaptor;
+import org.mockito.invocation.InvocationOnMock;
+import org.mockito.stubbing.Answer;
 
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyString;
 import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 /**
- * Tests for {@link DevicePolicyManager} and {@link DevicePolicyManagerService}.
+ * Tests for DevicePolicyManager( and DevicePolicyManagerService).
  *
  m FrameworksServicesTests &&
  adb install \
@@ -51,9 +66,13 @@
  */
 public class DevicePolicyManagerTest extends DpmTestBase {
 
+
     private DpmMockContext mContext;
     public DevicePolicyManager dpm;
     public DevicePolicyManagerServiceTestable dpms;
+    public ComponentName admin1;
+    public ComponentName admin2;
+    public ComponentName admin3;
 
     @Override
     protected void setUp() throws Exception {
@@ -67,9 +86,142 @@
         LocalServices.removeServiceForTest(DevicePolicyManagerInternal.class);
         dpms = new DevicePolicyManagerServiceTestable(mContext, dataDir);
         dpm = new DevicePolicyManagerTestable(mContext, dpms);
+
+        admin1 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin1.class);
+        admin2 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin2.class);
+        admin3 = new ComponentName(mRealTestContext, DummyDeviceAdmins.Admin3.class);
+
+        setUpPackageManagerForAdmin(admin1);
+        setUpPackageManagerForAdmin(admin2);
+        setUpPackageManagerForAdmin(admin3);
+
+        setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED);
+        setUpPackageInfo();
+        setUpUserManager();
     }
 
-    public void testHasNoFeature() {
+    /**
+     * Set up a mock result for {@link PackageManager#queryBroadcastReceivers}.  We'll return
+     * the actual ResolveInfo for the admin component, but we need to mock PM so it'll return
+     * it for user {@link DpmMockContext#CALLER_USER_HANDLE}.
+     */
+    private void setUpPackageManagerForAdmin(ComponentName admin) {
+        final Intent resolveIntent = new Intent();
+        resolveIntent.setComponent(admin);
+        final List<ResolveInfo> realResolveInfo =
+                mRealTestContext.getPackageManager().queryBroadcastReceivers(
+                        resolveIntent,
+                        PackageManager.GET_META_DATA);
+        assertNotNull(realResolveInfo);
+        assertEquals(1, realResolveInfo.size());
+
+        // We need to rewrite the UID in the activity info.
+        realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
+
+        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
+                MockUtils.checkIntentComponent(admin),
+                eq(PackageManager.GET_META_DATA
+                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(DpmMockContext.CALLER_USER_HANDLE)
+        );
+    }
+
+    /**
+     * Set up a mock result for {@link IPackageManager#getApplicationInfo} for user
+     * {@link DpmMockContext#CALLER_USER_HANDLE}.
+     */
+    private void setUpApplicationInfo(int enabledSetting) throws Exception {
+        final ApplicationInfo ai = mRealTestContext.getPackageManager().getApplicationInfo(
+                admin1.getPackageName(),
+                PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
+
+        ai.enabledSetting = enabledSetting;
+
+        doReturn(ai).when(mContext.ipackageManager).getApplicationInfo(
+                eq(admin1.getPackageName()),
+                eq(PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
+    }
+
+    /**
+     * Set up a mock result for {@link IPackageManager#getPackageInfo(String, int, int)} for user
+     * {@link DpmMockContext#CALLER_USER_HANDLE} as well as the system user.
+     */
+    private void setUpPackageInfo() throws Exception {
+        final PackageInfo pi = mRealTestContext.getPackageManager().getPackageInfo(
+                admin1.getPackageName(), 0);
+        assertTrue(pi.applicationInfo.flags != 0);
+
+        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+                eq(admin1.getPackageName()),
+                eq(0),
+                eq(DpmMockContext.CALLER_USER_HANDLE));
+        doReturn(pi).when(mContext.ipackageManager).getPackageInfo(
+                eq(admin1.getPackageName()),
+                eq(0),
+                eq(UserHandle.USER_SYSTEM));
+    }
+
+    private void setUpUserManager() {
+        // Emulate UserManager.set/getApplicationRestriction().
+        final Map<Pair<String, UserHandle>, Bundle> appRestrictions = new HashMap<>();
+
+        // UM.setApplicationRestrictions() will save to appRestrictions.
+        doAnswer(new Answer<Void>() {
+            @Override
+            public Void answer(InvocationOnMock invocation) throws Throwable {
+                String pkg = (String) invocation.getArguments()[0];
+                Bundle bundle = (Bundle) invocation.getArguments()[1];
+                UserHandle user = (UserHandle) invocation.getArguments()[2];
+
+                appRestrictions.put(Pair.create(pkg, user), bundle);
+
+                return null;
+            }
+        }).when(mContext.userManager).setApplicationRestrictions(
+                anyString(), any(Bundle.class), any(UserHandle.class));
+
+        // UM.getApplicationRestrictions() will read from appRestrictions.
+        doAnswer(new Answer<Bundle>() {
+            @Override
+            public Bundle answer(InvocationOnMock invocation) throws Throwable {
+                String pkg = (String) invocation.getArguments()[0];
+                UserHandle user = (UserHandle) invocation.getArguments()[1];
+
+                return appRestrictions.get(Pair.create(pkg, user));
+            }
+        }).when(mContext.userManager).getApplicationRestrictions(
+                anyString(), any(UserHandle.class));
+
+        // System user is always running.
+        when(mContext.userManager.isUserRunning(MockUtils.checkUserHandle(UserHandle.USER_SYSTEM)))
+                .thenReturn(true);
+
+        // Set up (default) UserInfo for CALLER_USER_HANDLE.
+        final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE,
+                "user" + DpmMockContext.CALLER_USER_HANDLE, 0);
+
+        when(mContext.userManager.getUserInfo(eq(DpmMockContext.CALLER_USER_HANDLE)))
+                .thenReturn(uh);
+    }
+
+    private void setAsProfileOwner(ComponentName admin) {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+
+        final UserInfo uh = new UserInfo(DpmMockContext.CALLER_USER_HANDLE, "user", 0);
+
+        // DO needs to be an DA.
+        dpm.setActiveAdmin(admin, /* replace =*/ false);
+
+        // Fire!
+        assertTrue(dpm.setProfileOwner(admin, "owner-name", DpmMockContext.CALLER_USER_HANDLE));
+
+        // Check
+        assertEquals(admin1, dpm.getProfileOwnerAsUser(DpmMockContext.CALLER_USER_HANDLE));
+    }
+
+    public void testHasNoFeature() throws Exception {
         when(mContext.packageManager.hasSystemFeature(eq(PackageManager.FEATURE_DEVICE_ADMIN)))
                 .thenReturn(false);
 
@@ -84,13 +236,11 @@
      * Caller doesn't have proper permissions.
      */
     public void testSetActiveAdmin_SecurityException() {
-        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
-
         // 1. Failure cases.
 
         // Caller doesn't have MANAGE_DEVICE_ADMINS.
         try {
-            dpm.setActiveAdmin(admin, false);
+            dpm.setActiveAdmin(admin1, false);
             fail("Didn't throw SecurityException");
         } catch (SecurityException expected) {
         }
@@ -98,62 +248,345 @@
         // Caller has MANAGE_DEVICE_ADMINS, but for different user.
         mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
         try {
-            dpm.setActiveAdmin(admin, false, DpmMockContext.CALLER_USER_HANDLE + 1);
+            dpm.setActiveAdmin(admin1, false, DpmMockContext.CALLER_USER_HANDLE + 1);
             fail("Didn't throw SecurityException");
         } catch (SecurityException expected) {
         }
     }
 
-    public void testSetActiveAdmin() {
-        final ComponentName admin = new ComponentName(mRealTestContext, DummyDeviceAdmin.class);
-
-        // 1. Prepare mock package manager (and other mocks)
-
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#setActiveAdmin}
+     *   with replace=false and replace=true
+     * {@link DevicePolicyManager#isAdminActive}
+     * {@link DevicePolicyManager#isAdminActiveAsUser}
+     * {@link DevicePolicyManager#getActiveAdmins}
+     * {@link DevicePolicyManager#getActiveAdminsAsUser}
+     */
+    public void testSetActiveAdmin() throws Exception {
+        // 1. Make sure the caller has proper permissions.
         mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
 
-        // Create ResolveInfo for the admin.
-        final Intent resolveIntent = new Intent();
-        resolveIntent.setComponent(admin);
-        final List<ResolveInfo> realResolveInfo =
-                mRealTestContext.getPackageManager().queryBroadcastReceivers(
-                        resolveIntent,
-                        PackageManager.GET_META_DATA
-                            | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS);
-        assertNotNull(realResolveInfo);
-        assertEquals(1, realResolveInfo.size());
-
-        // We need to rewrite the UID in the activity info.
-        realResolveInfo.get(0).activityInfo.applicationInfo.uid = DpmMockContext.CALLER_UID;
-
-        doReturn(realResolveInfo).when(mContext.packageManager).queryBroadcastReceivers(
-                any(Intent.class), // TODO check the intent too.
-                eq(PackageManager.GET_META_DATA
-                        | PackageManager.GET_DISABLED_UNTIL_USED_COMPONENTS),
-                eq(DpmMockContext.CALLER_USER_HANDLE)
-        );
-
-        // 2. Everything is ready; call the method.
-        dpm.setActiveAdmin(admin, false);
+        // 2. Call the API.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
 
         // 3. Verify internal calls.
 
         // Check if the boradcast is sent.
-        final ArgumentCaptor<Intent> intentCap = ArgumentCaptor.forClass(Intent.class);
-        final ArgumentCaptor<UserHandle> uhCap = ArgumentCaptor.forClass(UserHandle.class);
-
-        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
-                intentCap.capture(),
+        verify(mContext.spiedContext).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+        verify(mContext.spiedContext).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED),
                 MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
 
-        // First call from saveSettingsLocked().
-        assertEquals(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED,
-                intentCap.getAllValues().get(0).getAction());
-
-        // Second call from setActiveAdmin/sendAdminCommandLocked()
-        assertEquals(DeviceAdminReceiver.ACTION_DEVICE_ADMIN_ENABLED,
-                intentCap.getAllValues().get(1).getAction());
+        verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
+                eq(admin1.getPackageName()),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+                eq(PackageManager.DONT_KILL_APP),
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                anyString());
 
         // TODO Verify other calls too.
+
+        // Make sure it's active admin1.
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isAdminActive(admin2));
+        assertFalse(dpm.isAdminActive(admin3));
+
+        // But not admin1 for a different user.
+
+        // For this to work, caller needs android.permission.INTERACT_ACROSS_USERS_FULL.
+        // (Because we're checking a different user's status from CALLER_USER_HANDLE.)
+        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+        assertFalse(dpm.isAdminActiveAsUser(admin1, DpmMockContext.CALLER_USER_HANDLE + 1));
+        assertFalse(dpm.isAdminActiveAsUser(admin2, DpmMockContext.CALLER_USER_HANDLE + 1));
+
+        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+        // Next, add one more admin.
+        // Before doing so, update the application info, now it's enabled.
+        setUpApplicationInfo(PackageManager.COMPONENT_ENABLED_STATE_ENABLED);
+
+        dpm.setActiveAdmin(admin2, /* replace =*/ false);
+
+        // Now we have two admins.
+        assertTrue(dpm.isAdminActive(admin1));
+        assertTrue(dpm.isAdminActive(admin2));
+        assertFalse(dpm.isAdminActive(admin3));
+
+        // Admin2 was already enabled, so setApplicationEnabledSetting() shouldn't have called
+        // again.  (times(1) because it was previously called for admin1)
+        verify(mContext.ipackageManager, times(1)).setApplicationEnabledSetting(
+                eq(admin1.getPackageName()),
+                eq(PackageManager.COMPONENT_ENABLED_STATE_DEFAULT),
+                eq(PackageManager.DONT_KILL_APP),
+                eq(DpmMockContext.CALLER_USER_HANDLE),
+                anyString());
+
+        // 4. Add the same admin1 again without replace, which should throw.
+        try {
+            dpm.setActiveAdmin(admin1, /* replace =*/ false);
+            fail("Didn't throw");
+        } catch (IllegalArgumentException expected) {
+        }
+
+        // 5. Add the same admin1 again with replace, which should succeed.
+        dpm.setActiveAdmin(admin1, /* replace =*/ true);
+
+        // TODO make sure it's replaced.
+
+        // 6. Test getActiveAdmins()
+        List<ComponentName> admins = dpm.getActiveAdmins();
+        assertEquals(2, admins.size());
+        assertEquals(admin1, admins.get(0));
+        assertEquals(admin2, admins.get(1));
+
+        // Another user has no admins.
+        mContext.callerPermissions.add("android.permission.INTERACT_ACROSS_USERS_FULL");
+
+        assertEquals(0, DpmTestUtils.getListSizeAllowingNull(
+                dpm.getActiveAdminsAsUser(DpmMockContext.CALLER_USER_HANDLE + 1)));
+
+        mContext.callerPermissions.remove("android.permission.INTERACT_ACROSS_USERS_FULL");
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#setActiveAdmin}
+     *   with replace=false
+     */
+    public void testSetActiveAdmin_twiceWithoutReplace() throws Exception {
+        // 1. Make sure the caller has proper permissions.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        assertTrue(dpm.isAdminActive(admin1));
+
+        // Add the same admin1 again without replace, which should throw.
+        try {
+            dpm.setActiveAdmin(admin1, /* replace =*/ false);
+            fail("Didn't throw");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#removeActiveAdmin}
+     */
+    public void testRemoveActiveAdmin_SecurityException() {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin.
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Directly call the DPMS method with a different userid, which should fail.
+        try {
+            dpms.removeActiveAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE + 1);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+
+        // Try to remove active admin with a different caller userid should fail too, without
+        // having MANAGE_DEVICE_ADMINS.
+        mContext.callerPermissions.clear();
+
+        mContext.binder.callingUid = 1234567;
+        try {
+            dpm.removeActiveAdmin(admin1);
+            fail("Didn't throw SecurityException");
+        } catch (SecurityException expected) {
+        }
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#removeActiveAdmin}
+     */
+    public void testRemoveActiveAdmin_fromDifferentUserWithMINTERACT_ACROSS_USERS_FULL() {
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin1.
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Different user, but should work, because caller has proper permissions.
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+        mContext.binder.callingUid = 1234567;
+        dpm.removeActiveAdmin(admin1);
+
+        assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // TODO DO Still can't be removed in this case.
+    }
+
+    /**
+     * Test for:
+     * {@link DevicePolicyManager#removeActiveAdmin}
+     */
+    public void testRemoveActiveAdmin_sameUserNoMANAGE_DEVICE_ADMINS() {
+        // Need MANAGE_DEVICE_ADMINS for setActiveAdmin.  We'll remove it later.
+        mContext.callerPermissions.add(android.Manifest.permission.MANAGE_DEVICE_ADMINS);
+
+        // Add admin1.
+
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        assertTrue(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Broadcast from saveSettingsLocked().
+        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // Remove.  No permissions, but same user, so it'll work.
+        mContext.callerPermissions.clear();
+        dpm.removeActiveAdmin(admin1);
+
+        final ArgumentCaptor<BroadcastReceiver> brCap =
+                ArgumentCaptor.forClass(BroadcastReceiver.class);
+
+        // Is removing now, but not removed yet.
+        assertTrue(dpm.isAdminActive(admin1));
+        assertTrue(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        verify(mContext.spiedContext).sendOrderedBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DeviceAdminReceiver.ACTION_DEVICE_ADMIN_DISABLED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE),
+                isNull(String.class),
+                brCap.capture(),
+                eq(dpms.mHandler),
+                eq(Activity.RESULT_OK),
+                isNull(String.class),
+                isNull(Bundle.class));
+
+        brCap.getValue().onReceive(mContext, null);
+
+        assertFalse(dpm.isAdminActive(admin1));
+        assertFalse(dpm.isRemovingAdmin(admin1, DpmMockContext.CALLER_USER_HANDLE));
+
+        // Again broadcast from saveSettingsLocked().
+        verify(mContext.spiedContext, times(2)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(
+                        DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED),
+                MockUtils.checkUserHandle(DpmMockContext.CALLER_USER_HANDLE));
+
+        // TODO Check other internal calls.
+    }
+
+    /**
+     * Test for: {@link DevicePolicyManager#setDeviceOwner} DO on system user installs
+     * successfully.
+     */
+    public void testSetDeviceOwner() throws Exception {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+        // Call from a process on the system user.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        // DO needs to be an DA.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+
+        // Fire!
+        assertTrue(dpm.setDeviceOwner(admin1.getPackageName(), "owner-name"));
+
+        // Verify internal calls.
+        verify(mContext.iactivityManager, times(1)).updateDeviceOwner(
+                eq(admin1.getPackageName()));
+
+        // TODO We should check if the caller has called clearCallerIdentity().
+        verify(mContext.ibackupManager, times(1)).setBackupServiceActive(
+                eq(UserHandle.USER_SYSTEM), eq(false));
+
+        verify(mContext.spiedContext, times(1)).sendBroadcastAsUser(
+                MockUtils.checkIntentAction(DevicePolicyManager.ACTION_DEVICE_OWNER_CHANGED),
+                MockUtils.checkUserHandle(UserHandle.USER_SYSTEM));
+
+        assertEquals(admin1.getPackageName(), dpm.getDeviceOwner());
+
+        // TODO Test getDeviceOwnerName() too.  To do so, we need to change
+        // DPMS.getApplicationLabel() because Context.createPackageContextAsUser() is not mockable.
+    }
+
+    /**
+     * Test for: {@link DevicePolicyManager#setDeviceOwner} Package doesn't exist.
+     */
+    public void testSetDeviceOwner_noSuchPackage() {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        mContext.callerPermissions.add(permission.MANAGE_PROFILE_AND_DEVICE_OWNERS);
+        mContext.callerPermissions.add(permission.INTERACT_ACROSS_USERS_FULL);
+
+        // Call from a process on the system user.
+        mContext.binder.callingUid = DpmMockContext.CALLER_SYSTEM_USER_UID;
+
+        // DO needs to be an DA.
+        dpm.setActiveAdmin(admin1, /* replace =*/ false);
+        try {
+            dpm.setDeviceOwner("a.b.c");
+            fail("Didn't throw IllegalArgumentException");
+        } catch (IllegalArgumentException expected) {
+        }
+    }
+
+    public void testSetDeviceOwner_failures() throws Exception {
+        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetDeviceOwner().
+    }
+
+    public void testSetProfileOwner() throws Exception {
+        setAsProfileOwner(admin1);
+    }
+
+    public void testSetProfileOwner_failures() throws Exception {
+        // TODO Test more failure cases.  Basically test all chacks in enforceCanSetProfileOwner().
+    }
+
+    public void testSetGetApplicationRestriction() {
+        setAsProfileOwner(admin1);
+
+        {
+            Bundle rest = new Bundle();
+            rest.putString("KEY_STRING", "Foo1");
+            dpm.setApplicationRestrictions(admin1, "pkg1", rest);
+        }
+
+        {
+            Bundle rest = new Bundle();
+            rest.putString("KEY_STRING", "Foo2");
+            dpm.setApplicationRestrictions(admin1, "pkg2", rest);
+        }
+
+        {
+            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg1");
+            assertNotNull(returned);
+            assertEquals(returned.size(), 1);
+            assertEquals(returned.get("KEY_STRING"), "Foo1");
+        }
+
+        {
+            Bundle returned = dpm.getApplicationRestrictions(admin1, "pkg2");
+            assertNotNull(returned);
+            assertEquals(returned.size(), 1);
+            assertEquals(returned.get("KEY_STRING"), "Foo2");
+        }
+
+        dpm.setApplicationRestrictions(admin1, "pkg2", new Bundle());
+        assertEquals(0, dpm.getApplicationRestrictions(admin1, "pkg2").size());
     }
 }
-
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
index 8644311..3b30a37 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmMockContext.java
@@ -20,11 +20,14 @@
 
 import android.app.IActivityManager;
 import android.app.NotificationManager;
+import android.app.backup.IBackupManager;
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
+import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
+import android.media.IAudioService;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.PowerManager.WakeLock;
@@ -34,6 +37,8 @@
 import android.test.mock.MockContext;
 import android.view.IWindowManager;
 
+import org.junit.Assert;
+
 import java.io.File;
 import java.util.ArrayList;
 import java.util.List;
@@ -51,11 +56,16 @@
     public static final int CALLER_USER_HANDLE = 20;
 
     /**
-     * UID of the caller.
+     * UID corresponding to {@link #CALLER_USER_HANDLE}.
      */
     public static final int CALLER_UID = UserHandle.PER_USER_RANGE * CALLER_USER_HANDLE + 123;
 
     /**
+     * UID used when a caller is on the system user.
+     */
+    public static final int CALLER_SYSTEM_USER_UID = 123;
+
+    /**
      * PID of the caller.
      */
     public static final int CALLER_PID = 22222;
@@ -71,27 +81,27 @@
     public static final int SYSTEM_PID = 11111;
 
     public static class MockBinder {
-        int mCallingUid = CALLER_UID;
-        int mCallingPid = CALLER_PID;
+        public int callingUid = CALLER_UID;
+        public int callingPid = CALLER_PID;
 
         public long clearCallingIdentity() {
-            final long token = (((long) mCallingUid) << 32) | (mCallingPid);
-            mCallingUid = SYSTEM_UID;
-            mCallingPid = SYSTEM_PID;
+            final long token = (((long) callingUid) << 32) | (callingPid);
+            callingUid = SYSTEM_UID;
+            callingPid = SYSTEM_PID;
             return token;
         }
 
         public void restoreCallingIdentity(long token) {
-            mCallingUid = (int) (token >> 32);
-            mCallingPid = (int) token;
+            callingUid = (int) (token >> 32);
+            callingPid = (int) token;
         }
 
         public int getCallingUid() {
-            return mCallingUid;
+            return callingUid;
         }
 
         public int getCallingPid() {
-            return mCallingPid;
+            return callingPid;
         }
 
         public UserHandle getCallingUserHandle() {
@@ -99,7 +109,7 @@
         }
 
         public boolean isCallerUidMyUid() {
-            return mCallingUid == SYSTEM_UID;
+            return callingUid == SYSTEM_UID;
         }
     }
 
@@ -118,6 +128,33 @@
         }
     }
 
+    public static class SystemPropertiesForMock {
+        public boolean getBoolean(String key, boolean def) {
+            return false;
+        }
+
+        public long getLong(String key, long def) {
+            return 0;
+        }
+
+        public String get(String key, String def) {
+            return null;
+        }
+
+        public String get(String key) {
+            return null;
+        }
+
+        public void set(String key, String value) {
+        }
+    }
+
+    public static class UserManagerForMock {
+        public boolean isSplitSystemUser() {
+            return false;
+        }
+    }
+
     public final Context realTestContext;
 
     /**
@@ -129,12 +166,17 @@
 
     public final MockBinder binder;
     public final EnvironmentForMock environment;
+    public final SystemPropertiesForMock systemProperties;
     public final UserManager userManager;
+    public final UserManagerForMock userManagerForMock;
     public final PowerManagerForMock powerManager;
     public final PowerManagerInternal powerManagerInternal;
     public final NotificationManager notificationManager;
     public final IWindowManager iwindowManager;
     public final IActivityManager iactivityManager;
+    public final IPackageManager ipackageManager;
+    public final IBackupManager ibackupManager;
+    public final IAudioService iaudioService;
     public final LockPatternUtils lockPatternUtils;
 
     /** Note this is a partial mock, not a real mock. */
@@ -146,12 +188,17 @@
         realTestContext = context;
         binder = new MockBinder();
         environment = mock(EnvironmentForMock.class);
+        systemProperties= mock(SystemPropertiesForMock.class);
         userManager = mock(UserManager.class);
+        userManagerForMock = mock(UserManagerForMock.class);
         powerManager = mock(PowerManagerForMock.class);
         powerManagerInternal = mock(PowerManagerInternal.class);
         notificationManager = mock(NotificationManager.class);
         iwindowManager = mock(IWindowManager.class);
         iactivityManager = mock(IActivityManager.class);
+        ipackageManager = mock(IPackageManager.class);
+        ibackupManager = mock(IBackupManager.class);
+        iaudioService = mock(IAudioService.class);
         lockPatternUtils = mock(LockPatternUtils.class);
 
         // Package manager is huge, so we use a partial mock instead.
@@ -172,6 +219,11 @@
     }
 
     @Override
+    public String getSystemServiceName(Class<?> serviceClass) {
+        return realTestContext.getSystemServiceName(serviceClass);
+    }
+
+    @Override
     public PackageManager getPackageManager() {
         return packageManager;
     }
@@ -244,6 +296,13 @@
 
     @Override
     public void sendBroadcastAsUser(Intent intent, UserHandle user) {
+        if (binder.callingPid != SYSTEM_PID) {
+            // Unless called as the system process, can only call if the target user is the
+            // calling user.
+            // (The actual check is more complex; we may need to change it later.)
+            Assert.assertEquals(UserHandle.getUserId(binder.getCallingUid()), user.getIdentifier());
+        }
+
         spiedContext.sendBroadcastAsUser(intent, user);
     }
 
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
index 77270c8..6f9f6ab 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestBase.java
@@ -21,7 +21,7 @@
 
 import java.io.File;
 
-public class DpmTestBase extends AndroidTestCase {
+public abstract class DpmTestBase extends AndroidTestCase {
     public static final String TAG = "DpmTest";
 
     protected Context mRealTestContext;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
index a8e2c3c..44a851a 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DpmTestUtils.java
@@ -23,6 +23,7 @@
 import org.junit.Assert;
 
 import java.io.File;
+import java.util.List;
 
 public class DpmTestUtils {
     private DpmTestUtils() {
@@ -33,6 +34,11 @@
             Assert.assertTrue("failed to delete dir", FileUtils.deleteContents(dir));
         }
         dir.mkdirs();
+        Log.i(DpmTestBase.TAG, "Created " + dir);
+    }
+
+    public static int getListSizeAllowingNull(List<?> list) {
+        return list == null ? 0 : list.size();
     }
 
     public static Printer LOG_PRINTER = new Printer() {
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
similarity index 75%
rename from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
rename to services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
index c47d194..08293a2 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmins.java
@@ -17,5 +17,11 @@
 
 import android.app.admin.DeviceAdminReceiver;
 
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
+public class DummyDeviceAdmins {
+    public static class Admin1 extends DeviceAdminReceiver {
+    }
+    public static class Admin2 extends DeviceAdminReceiver {
+    }
+    public static class Admin3 extends DeviceAdminReceiver {
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
index f2a2bf7..5008fbf 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/MockUtils.java
@@ -17,6 +17,8 @@
 
 import com.google.common.base.Objects;
 
+import android.content.ComponentName;
+import android.content.Intent;
 import android.os.UserHandle;
 
 import org.hamcrest.BaseMatcher;
@@ -44,4 +46,35 @@
         return Mockito.argThat(m);
     }
 
+    public static Intent checkIntentComponent(final ComponentName component) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return Objects.equal(((Intent) item).getComponent(), component);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Intent: component=\"" + component + "\"");
+            }
+        };
+        return Mockito.argThat(m);
+    }
+
+    public static Intent checkIntentAction(final String action) {
+        final Matcher<Intent> m = new BaseMatcher<Intent>() {
+            @Override
+            public boolean matches(Object item) {
+                if (item == null) return false;
+                return Objects.equal(((Intent) item).getAction(), action);
+            }
+
+            @Override
+            public void describeTo(Description description) {
+                description.appendText("Intent: action=\"" + action + "\"");
+            }
+        };
+        return Mockito.argThat(m);
+    }
 }
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 8779462..a8f2aca 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -14,6 +14,7 @@
 
 package android.telecom;
 
+import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
@@ -116,6 +117,15 @@
             "android.telecom.action.PHONE_ACCOUNT_REGISTERED";
 
     /**
+     * The {@link android.content.Intent} action used indicate that a phone account was
+     * just unregistered.
+     * @hide
+     */
+    @SystemApi
+    public static final String ACTION_PHONE_ACCOUNT_UNREGISTERED =
+            "android.telecom.action.PHONE_ACCOUNT_UNREGISTERED";
+
+    /**
      * Activity action: Shows a dialog asking the user whether or not they want to replace the
      * current default Dialer with the one specified in
      * {@link #EXTRA_CHANGE_DEFAULT_DIALER_PACKAGE_NAME}.
@@ -472,9 +482,12 @@
      * <p>
      * If no {@link PhoneAccount} fits the criteria above, this method will return {@code null}.
      *
+     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
      * @param uriScheme The URI scheme.
      * @return The {@link PhoneAccountHandle} corresponding to the account to be used.
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public PhoneAccountHandle getDefaultOutgoingPhoneAccount(String uriScheme) {
         try {
             if (isServiceConnected()) {
@@ -606,9 +619,12 @@
      * calls. The returned list includes only those accounts which have been explicitly enabled
      * by the user.
      *
+     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
      * @see #EXTRA_PHONE_ACCOUNT_HANDLE
      * @return A list of {@code PhoneAccountHandle} objects.
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public List<PhoneAccountHandle> getCallCapablePhoneAccounts() {
         return getCallCapablePhoneAccounts(false);
     }
@@ -881,9 +897,12 @@
      * Return whether a given phone number is the configured voicemail number for a
      * particular phone account.
      *
+     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
      * @param accountHandle The handle for the account to check the voicemail number against
      * @param number The number to look up.
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public boolean isVoiceMailNumber(PhoneAccountHandle accountHandle, String number) {
         try {
             if (isServiceConnected()) {
@@ -899,10 +918,13 @@
     /**
      * Return the voicemail number for a given phone account.
      *
+     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
      * @param accountHandle The handle for the phone account.
      * @return The voicemail number for the phone account, and {@code null} if one has not been
      *         configured.
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getVoiceMailNumber(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
@@ -918,9 +940,12 @@
     /**
      * Return the line 1 phone number for given phone account.
      *
+     * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
+     *
      * @param accountHandle The handle for the account retrieve a number for.
      * @return A string representation of the line 1 phone number.
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public String getLine1Number(PhoneAccountHandle accountHandle) {
         try {
             if (isServiceConnected()) {
@@ -940,6 +965,7 @@
      * Requires permission: {@link android.Manifest.permission#READ_PHONE_STATE}
      * </p>
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public boolean isInCall() {
         try {
             if (isServiceConnected()) {
@@ -1031,7 +1057,10 @@
 
     /**
      * Silences the ringer if a ringing call exists.
+     *
+     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void silenceRinger() {
         try {
             if (isServiceConnected()) {
@@ -1136,9 +1165,12 @@
      * Requires that the method-caller be set as the system dialer app.
      * </p>
      *
+     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     *
      * @param dialString The digits to dial.
      * @return True if the digits were processed as an MMI code, false otherwise.
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean handleMmi(String dialString) {
         ITelecomService service = getTelecomService();
         if (service != null) {
@@ -1159,10 +1191,13 @@
      * Requires that the method-caller be set as the system dialer app.
      * </p>
      *
+     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     *
      * @param accountHandle The handle for the account the MMI code should apply to.
      * @param dialString The digits to dial.
      * @return True if the digits were processed as an MMI code, false otherwise.
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public boolean handleMmi(String dialString, PhoneAccountHandle accountHandle) {
         ITelecomService service = getTelecomService();
         if (service != null) {
@@ -1177,11 +1212,14 @@
     }
 
     /**
+     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
+     *
      * @param accountHandle The handle for the account to derive an adn query URI for or
      * {@code null} to return a URI which will use the default account.
      * @return The URI (with the content:// scheme) specific to the specified {@link PhoneAccount}
      * for the the content retrieve.
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public Uri getAdnUriForPhoneAccount(PhoneAccountHandle accountHandle) {
         ITelecomService service = getTelecomService();
         if (service != null && accountHandle != null) {
@@ -1199,7 +1237,10 @@
      * <p>
      * Requires that the method-caller be set as the system dialer app.
      * </p>
+     *
+     * Requires permission: {@link android.Manifest.permission#MODIFY_PHONE_STATE}
      */
+    @RequiresPermission(android.Manifest.permission.MODIFY_PHONE_STATE)
     public void cancelMissedCallsNotification() {
         ITelecomService service = getTelecomService();
         if (service != null) {
@@ -1221,6 +1262,7 @@
      *
      * @param showDialpad Brings up the in-call dialpad as part of showing the in-call screen.
      */
+    @RequiresPermission(android.Manifest.permission.READ_PHONE_STATE)
     public void showInCallScreen(boolean showDialpad) {
         ITelecomService service = getTelecomService();
         if (service != null) {
@@ -1262,6 +1304,7 @@
      * @param address The address to make the call to.
      * @param extras Bundle of extras to use with the call.
      */
+    @RequiresPermission(android.Manifest.permission.CALL_PHONE)
     public void placeCall(Uri address, Bundle extras) {
         ITelecomService service = getTelecomService();
         if (service != null) {
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 1ff621a..17c24af 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -63,8 +63,14 @@
 public class MockPackageManager extends PackageManager {
 
     @Override
-    public PackageInfo getPackageInfo(String packageName, int flags)
-    throws NameNotFoundException {
+    public PackageInfo getPackageInfo(String packageName, int flags) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
 
@@ -524,6 +530,14 @@
         throw new UnsupportedOperationException();
     }
 
+    /** @hide */
+    @Override
+    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,
+            int flags, String installerPackageName, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
+
     @Override
     public void setInstallerPackageName(String targetPackage,
             String installerPackageName) {
@@ -629,6 +643,15 @@
         throw new UnsupportedOperationException();
     }
 
+    /**
+     * @hide - to match hiding in superclass
+     */
+    @Override
+    public void deletePackageAsUser(
+            String packageName, IPackageDeleteObserver observer, int flags, int userId) {
+        throw new UnsupportedOperationException();
+    }
+
     @Override
     public void addPackageToPreferred(String packageName) {
         throw new UnsupportedOperationException();
@@ -792,7 +815,15 @@
      * @hide
      */
     @Override
-    public int installExistingPackage(String packageName)
+    public int installExistingPackage(String packageName) throws NameNotFoundException {
+        throw new UnsupportedOperationException();
+    }
+
+    /**
+     * @hide
+     */
+    @Override
+    public int installExistingPackageAsUser(String packageName, int userId)
             throws NameNotFoundException {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
index 0b43666..8085db7 100644
--- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/CameraActivity.java
@@ -31,5 +31,7 @@
         super.onCreate(savedInstanceState);
         setContentView(R.layout.camera_activity);
         Log.i(TAG, "Activity created");
+        Log.i(TAG, "Source: "
+                + getIntent().getStringExtra("com.android.systemui.camera_launch_source"));
     }
 }
diff --git a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
index 530fe00..242d3b2 100644
--- a/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
+++ b/tests/CameraPrewarmTest/src/com/google/android/test/cameraprewarm/SecureCameraActivity.java
@@ -17,6 +17,7 @@
 package com.google.android.test.cameraprewarm;
 
 import android.app.Activity;
+import android.graphics.Camera;
 import android.os.Bundle;
 import android.util.Log;
 import android.view.WindowManager;
@@ -31,5 +32,7 @@
         setContentView(R.layout.camera_activity);
         getWindow().addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED);
         Log.i(CameraActivity.TAG, "Activity created");
+        Log.i(CameraActivity.TAG, "Source: "
+                + getIntent().getStringExtra("com.android.systemui.camera_launch_source"));
     }
 }
diff --git a/tests/WindowAnimationJank/Android.mk b/tests/WindowAnimationJank/Android.mk
new file mode 100644
index 0000000..888ae64
--- /dev/null
+++ b/tests/WindowAnimationJank/Android.mk
@@ -0,0 +1,31 @@
+# Copyright (C) 2015 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.
+
+LOCAL_PATH:= $(call my-dir)
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PACKAGE_NAME := WindowAnimationJank
+
+LOCAL_STATIC_JAVA_LIBRARIES := ub-uiautomator ub-janktesthelper
+
+LOCAL_SDK_VERSION := current
+
+include $(BUILD_PACKAGE)
diff --git a/tests/WindowAnimationJank/AndroidManifest.xml b/tests/WindowAnimationJank/AndroidManifest.xml
new file mode 100644
index 0000000..d7aef33
--- /dev/null
+++ b/tests/WindowAnimationJank/AndroidManifest.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ -->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+        package="android.windowanimationjank">
+
+  <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+
+  <application>
+      <uses-library android:name="android.test.runner"/>
+      <activity android:name="ElementLayoutActivity"
+                android:label="ElementLayoutActivity"
+                android:taskAffinity="android.windowanimationjank.ElementLayoutActivity" >
+          <intent-filter>
+              <action android:name="android.intent.action.MAIN" />
+              <category android:name="android.intent.category.LAUNCHER" />
+          </intent-filter>
+      </activity>
+  </application>
+
+    <!--  self-instrumenting test package. -->
+    <instrumentation android:name="android.test.InstrumentationTestRunner"
+                     android:targetPackage="android.windowanimationjank">
+    </instrumentation>
+
+</manifest>
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java b/tests/WindowAnimationJank/res/layout/flowlayout.xml
similarity index 67%
copy from services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
copy to tests/WindowAnimationJank/res/layout/flowlayout.xml
index c47d194..f2b559b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DummyDeviceAdmin.java
+++ b/tests/WindowAnimationJank/res/layout/flowlayout.xml
@@ -1,4 +1,5 @@
-/*
+<?xml version="1.0" encoding="utf-8"?>
+<!--
  * Copyright (C) 2015 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -12,10 +13,9 @@
  * 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.devicepolicy;
-
-import android.app.admin.DeviceAdminReceiver;
-
-public class DummyDeviceAdmin extends DeviceAdminReceiver {
-}
+ -->
+<android.windowanimationjank.FlowLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/root_flow_layout"
+        android:layout_width="fill_parent"
+        android:layout_height="fill_parent" />
\ No newline at end of file
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java b/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java
new file mode 100644
index 0000000..3b1fabc
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/ElementLayoutActivity.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2015 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.windowanimationjank;
+
+import java.util.Random;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.view.ViewTreeObserver.OnPreDrawListener;
+import android.widget.Chronometer;
+import android.widget.RadioButton;
+import android.widget.Switch;
+import android.widget.TextView;
+import android.widget.ToggleButton;
+
+/*
+ * Activity with arbitrary number of random UI elements, refresh itself constantly.
+ */
+public class ElementLayoutActivity extends Activity implements OnPreDrawListener {
+    public final static String NUM_ELEMENTS_KEY = "num_elements";
+
+    private final static int DEFAULT_NUM_ELEMENTS = 100;
+    private final static int BACKGROUND_COLOR = 0xfffff000;
+    private final static int INDICATOR_COLOR = 0xffff0000;
+
+    private FlowLayout mLayout;
+    // Use the constant seed in order to get predefined order of elements.
+    private Random mRandom = new Random(0);
+    // Blinker indicator for visual feedback that Activity is currently updating.
+    private TextView mIndicator;
+    private static float mIndicatorState;
+
+    @Override
+    protected void onCreate(final Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.flowlayout);
+
+        mLayout = (FlowLayout)findViewById(R.id.root_flow_layout);
+        mLayout.setBackgroundColor(BACKGROUND_COLOR);
+
+        mIndicator = new TextView(this);
+        mLayout.addView(mIndicator);
+        mIndicator.setText("***\n***");
+        mIndicator.setBackgroundColor(BACKGROUND_COLOR);
+        mIndicatorState = 0.0f;
+
+        // Need constantly invalidate view in order to get max redraw rate.
+        mLayout.getViewTreeObserver().addOnPreDrawListener(this);
+
+        // Read requested number of elements in layout.
+        int numElements = getIntent().getIntExtra(NUM_ELEMENTS_KEY, DEFAULT_NUM_ELEMENTS);
+
+        for (int i = 0; i < numElements; ++i) {
+            switch (mRandom.nextInt(5)) {
+            case 0:
+                createRadioButton();
+                break;
+            case 1:
+                createToggleButton();
+                break;
+            case 2:
+                createSwitch();
+                break;
+            case 3:
+                createTextView();
+                break;
+            case 4:
+                createChronometer();
+                break;
+            }
+        }
+
+        setContentView(mLayout);
+    }
+
+    private void createTextView() {
+        TextView textView = new TextView(this);
+        int lineCnt = mRandom.nextInt(4);
+        StringBuffer buffer = new StringBuffer();
+        for (int i = 0; i < lineCnt; ++i) {
+            if (i != 0) {
+                buffer.append("\n");
+            }
+            buffer.append("Line:" + mRandom.nextInt());
+        }
+        textView.setText(buffer);
+        mLayout.addView(textView);
+    }
+
+    private void createRadioButton() {
+        RadioButton button = new RadioButton(this);
+        button.setText("RadioButton:" + mRandom.nextInt());
+        mLayout.addView(button);
+    }
+
+    private void createToggleButton() {
+        ToggleButton button = new ToggleButton(this);
+        button.setChecked(mRandom.nextBoolean());
+        mLayout.addView(button);
+    }
+
+    private void createSwitch() {
+        Switch button = new Switch(this);
+        button.setChecked(mRandom.nextBoolean());
+        mLayout.addView(button);
+    }
+
+    private void createChronometer() {
+        Chronometer chronometer = new Chronometer(this);
+        chronometer.setBase(mRandom.nextLong());
+        mLayout.addView(chronometer);
+        chronometer.start();
+    }
+
+    @Override
+    protected void onResume() {
+        super.onResume();
+    }
+
+    @Override
+    protected void onPause() {
+        super.onPause();
+    }
+
+    @Override
+    public boolean onPreDraw() {
+        // Interpolate indicator color
+        int background = 0xff000000;
+        for (int i = 0; i < 3; ++i) {
+            int shift = 8 * i;
+            int colorB = (BACKGROUND_COLOR >> shift) & 0xff;
+            int colorI = (INDICATOR_COLOR >> shift) & 0xff;
+            int color = (int)((float)colorB * (1.0f - mIndicatorState) +
+                    (float)colorI * mIndicatorState);
+            if (color > 255) {
+                color = 255;
+            }
+            background |= (color << shift);
+        }
+
+        mIndicator.setBackgroundColor(background);
+        mIndicatorState += (3 / 60.0f);  // around 3 times per second
+        mIndicatorState = mIndicatorState - (int)mIndicatorState;
+
+        mLayout.postInvalidate();
+        return true;
+    }
+}
\ No newline at end of file
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java
new file mode 100644
index 0000000..9a2b9cc
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FlowLayout.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2015 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.windowanimationjank;
+
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * Custom layout that place all elements in flows with and automatically wraps them.
+ */
+public class FlowLayout extends ViewGroup {
+    private int mLineHeight;
+
+    public FlowLayout(Context context) {
+        super(context);
+    }
+
+    public FlowLayout(Context context, AttributeSet attrs) {
+        super(context, attrs);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        final int width =
+                MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() -getPaddingRight();
+        int height =
+                MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
+        final int count = getChildCount();
+
+        int x = getPaddingLeft();
+        int y = getPaddingTop();
+        int lineHeight = 0;
+
+        int childHeightMeasureSpec;
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
+        } else {
+            childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+        }
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST),
+                        childHeightMeasureSpec);
+                final int childWidth = child.getMeasuredWidth();
+                lineHeight = Math.max(lineHeight, child.getMeasuredHeight());
+
+                if (x + childWidth > width) {
+                    x = getPaddingLeft();
+                    y += lineHeight;
+                }
+
+                x += childWidth;
+            }
+        }
+        mLineHeight = lineHeight;
+
+        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
+            height = y + lineHeight;
+        } else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
+            if (y + lineHeight < height) {
+                height = y + lineHeight;
+            }
+        }
+        setMeasuredDimension(width, height);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        if (p instanceof LayoutParams) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final int count = getChildCount();
+        final int width = r - l;
+        int x = getPaddingLeft();
+        int y = getPaddingTop();
+
+        for (int i = 0; i < count; i++) {
+            final View child = getChildAt(i);
+            if (child.getVisibility() != GONE) {
+                final int childWidth = child.getMeasuredWidth();
+                final int childHeight = child.getMeasuredHeight();
+                if (x + childWidth > width) {
+                    x = getPaddingLeft();
+                    y += mLineHeight;
+                }
+                child.layout(x, y, x + childWidth, y + childHeight);
+                x += childWidth;
+            }
+        }
+    }
+}
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java
new file mode 100644
index 0000000..1fb502a
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/FullscreenRotationTest.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2015 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.windowanimationjank;
+
+import android.os.Bundle;
+import android.support.test.jank.JankTest;
+import android.support.test.jank.GfxMonitor;
+
+/**
+ * Detect janks during screen rotation for full-screen activity. Periodically change
+ * orientation from left to right and track ElementLayoutActivity rendering performance
+ * via GfxMonitor.
+ */
+public class FullscreenRotationTest extends WindowAnimationJankTestBase {
+    private final static int STEP_CNT = 3;
+
+    @Override
+    public void beforeTest() throws Exception {
+        getUiDevice().setOrientationLeft();
+        Utils.startElementLayout(getInstrumentation(), 100);
+        super.beforeTest();
+    }
+
+    @Override
+    public void afterTest(Bundle metrics) {
+        Utils.rotateDevice(getInstrumentation(), Utils.ROTATION_MODE_NATURAL);
+        super.afterTest(metrics);
+    }
+
+    @JankTest(expectedFrames=100, defaultIterationCount=2)
+    @GfxMonitor(processName=Utils.PACKAGE)
+    public void testRotation() throws Exception {
+        for (int i = 0; i < STEP_CNT; ++i) {
+            Utils.rotateDevice(getInstrumentation(),
+                    Utils.getDeviceRotation(getInstrumentation()) == Utils.ROTATION_MODE_LEFT ?
+                    Utils.ROTATION_MODE_RIGHT : Utils.ROTATION_MODE_LEFT);
+        }
+    }
+}
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java
new file mode 100644
index 0000000..2531464
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/Utils.java
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2015 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.windowanimationjank;
+
+import android.app.Instrumentation;
+import android.app.UiAutomation;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.SystemClock;
+import android.support.test.uiautomator.By;
+import android.support.test.uiautomator.BySelector;
+import android.support.test.uiautomator.UiDevice;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+/**
+ * Set of helpers to manipulate test activities.
+ */
+public class Utils {
+    protected final static String PACKAGE = "android.windowanimationjank";
+    protected final static String ELEMENT_LAYOUT_ACTIVITY = "ElementLayoutActivity";
+    protected final static String ELEMENT_LAYOUT_CLASS = PACKAGE + "." + ELEMENT_LAYOUT_ACTIVITY;
+    protected final static long WAIT_FOR_ACTIVITY_TIMEOUT = 10000;
+    private static final BySelector ROOT_ELEMENT_LAYOUT = By.res(PACKAGE, "root_flow_layout");
+
+    private final static long ROTATION_ANIMATION_TIME_FULL_SCREEN_MS = 1000;
+
+    protected final static int ROTATION_MODE_NATURAL = 0;
+    protected final static int ROTATION_MODE_LEFT = 1;
+    protected final static int ROTATION_MODE_RIGHT = 2;
+
+    private static UiObject2 waitForActivity(Instrumentation instrumentation, BySelector selector) {
+        UiDevice device = UiDevice.getInstance(instrumentation);
+        UiObject2 window = device.wait(Until.findObject(selector), WAIT_FOR_ACTIVITY_TIMEOUT);
+        if (window == null) {
+            throw new RuntimeException(selector.toString() + " has not been started.");
+        }
+
+        // Get root object.
+        while (window.getParent() != null) {
+            window = window.getParent();
+        }
+        return window;
+    }
+
+    public static UiObject2 waitForElementLayout(Instrumentation instrumentation) {
+        return waitForActivity(instrumentation, ROOT_ELEMENT_LAYOUT);
+    }
+
+    /**
+     * Start and return activity with requested number of random elements.
+     */
+    public static UiObject2 startElementLayout(Instrumentation instrumentation, int numElements) {
+        Intent intent = new Intent(Intent.ACTION_MAIN);
+        intent.setComponent(new ComponentName(PACKAGE, ELEMENT_LAYOUT_CLASS));
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        intent.putExtra(ElementLayoutActivity.NUM_ELEMENTS_KEY, numElements);
+        instrumentation.getTargetContext().startActivity(intent);
+        return waitForElementLayout(instrumentation);
+    }
+
+    public static int getDeviceRotation(Instrumentation instrumentation) {
+        try {
+            UiDevice device = UiDevice.getInstance(instrumentation);
+            switch (device.getDisplayRotation()) {
+            case UiAutomation.ROTATION_FREEZE_90:
+                return ROTATION_MODE_LEFT;
+            case UiAutomation.ROTATION_FREEZE_270:
+                return ROTATION_MODE_RIGHT;
+            case UiAutomation.ROTATION_FREEZE_0:
+            case UiAutomation.ROTATION_FREEZE_180:
+                return ROTATION_MODE_NATURAL;
+            }
+        } catch(Exception e) {
+            throw new RuntimeException();
+        }
+        throw new RuntimeException("Unsupported device rotation.");
+    }
+
+    public static void rotateDevice(Instrumentation instrumentation, int rotationMode) {
+        try {
+            UiDevice device = UiDevice.getInstance(instrumentation);
+            long startTime = System.currentTimeMillis();
+            switch (rotationMode) {
+            case ROTATION_MODE_NATURAL:
+                device.setOrientationNatural();
+                break;
+            case ROTATION_MODE_LEFT:
+                device.setOrientationLeft();
+                break;
+            case ROTATION_MODE_RIGHT:
+                device.setOrientationRight();
+                break;
+            default:
+                throw new RuntimeException("Unsupported rotation mode: " + rotationMode);
+            }
+
+            long toSleep = ROTATION_ANIMATION_TIME_FULL_SCREEN_MS -
+                    (System.currentTimeMillis() - startTime);
+            if (toSleep > 0) {
+                SystemClock.sleep(toSleep);
+            }
+        } catch(Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java
new file mode 100644
index 0000000..bf739fa
--- /dev/null
+++ b/tests/WindowAnimationJank/src/android/windowanimationjank/WindowAnimationJankTestBase.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2015 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.windowanimationjank;
+
+import java.io.IOException;
+import java.util.StringTokenizer;
+
+import android.support.test.jank.JankTestBase;
+import android.support.test.uiautomator.UiDevice;
+
+/**
+ * This adds additional system level jank monitor and its result is merged with primary monitor
+ * used in test.
+ */
+public abstract class WindowAnimationJankTestBase extends JankTestBase {
+    private static final String TAG = "WindowAnimationJankTestBase";
+
+    protected WindowAnimationJankTestBase() {
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        // fix device orientation
+        getUiDevice().setOrientationNatural();
+
+        // Start from the home screen
+        getUiDevice().pressHome();
+        getUiDevice().waitForIdle();
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        getUiDevice().unfreezeRotation();
+        super.tearDown();
+    }
+
+    protected UiDevice getUiDevice() {
+        return UiDevice.getInstance(getInstrumentation());
+    }
+}
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index b9e7500..a390b0c 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -175,16 +175,6 @@
         }
 
         try {
-            mWm.setAppWillBeHidden(null);
-            fail("IWindowManager.setAppWillBeHidden did not throw SecurityException as"
-                    + " expected");
-        } catch (SecurityException e) {
-            // expected
-        } catch (RemoteException e) {
-            fail("Unexpected remote exception");
-        }
-
-        try {
             mWm.setAppVisibility(null, false);
             fail("IWindowManager.setAppVisibility did not throw SecurityException as"
                     + " expected");
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
index 163fbcb..f4b1f2c 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeResources.java
@@ -48,9 +48,6 @@
 import java.io.InputStream;
 import java.util.Iterator;
 
-/**
- *
- */
 public final class BridgeResources extends Resources {
 
     private BridgeContext mContext;
@@ -278,7 +275,7 @@
      * always Strings. The ideal signature for the method should be &lt;T super String&gt;, but java
      * generics don't support it.
      */
-    private <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
+    <T extends CharSequence> T[] fillValues(ArrayResourceValue resValue, T[] values) {
         int i = 0;
         for (Iterator<String> iterator = resValue.iterator(); iterator.hasNext(); i++) {
             @SuppressWarnings("unchecked")
@@ -404,7 +401,7 @@
                     if (xml.isFile()) {
                         // we need to create a pull parser around the layout XML file, and then
                         // give that to our XmlBlockParser
-                        parser = ParserFactory.create(xml);
+                        parser = ParserFactory.create(xml, true);
                     }
                 }
 
diff --git a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
index 6a61090..31dd3d9 100644
--- a/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
+++ b/tools/layoutlib/bridge/src/android/content/res/BridgeTypedArray.java
@@ -16,6 +16,7 @@
 
 package android.content.res;
 
+import com.android.ide.common.rendering.api.ArrayResourceValue;
 import com.android.ide.common.rendering.api.AttrResourceValue;
 import com.android.ide.common.rendering.api.LayoutLog;
 import com.android.ide.common.rendering.api.RenderResources;
@@ -33,6 +34,7 @@
 import org.xmlpull.v1.XmlPullParserException;
 
 import android.annotation.Nullable;
+import android.content.res.Resources.NotFoundException;
 import android.content.res.Resources.Theme;
 import android.graphics.drawable.Drawable;
 import android.util.DisplayMetrics;
@@ -740,12 +742,20 @@
      */
     @Override
     public CharSequence[] getTextArray(int index) {
-        String value = getString(index);
-        if (value != null) {
-            return new CharSequence[] { value };
+        if (!hasValue(index)) {
+            return null;
         }
-
-        return null;
+        ResourceValue resVal = mResourceData[index];
+        if (resVal instanceof ArrayResourceValue) {
+            ArrayResourceValue array = (ArrayResourceValue) resVal;
+            int count = array.getElementCount();
+            return count >= 0 ? mBridgeResources.fillValues(array, new CharSequence[count]) : null;
+        }
+        int id = getResourceId(index, 0);
+        String resIdMessage = id > 0 ? " (resource id 0x" + Integer.toHexString(id) + ')' : "";
+        throw new NotFoundException(
+                String.format("%1$s in %2$s%3$s is not a valid array resource.",
+                        resVal.getValue(), mNames[index], resIdMessage));
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
index 857e6d0..c7b24bc 100644
--- a/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/FontFamily_Delegate.java
@@ -178,7 +178,9 @@
         desiredStyle.mIsItalic = isItalic;
         FontInfo bestFont = null;
         int bestMatch = Integer.MAX_VALUE;
-        for (FontInfo font : mFonts) {
+        //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
+        for (int i = 0, n = mFonts.size(); i < n; i++) {
+            FontInfo font = mFonts.get(i);
             int match = computeMatch(font, desiredStyle);
             if (match < bestMatch) {
                 bestMatch = match;
@@ -415,7 +417,9 @@
         boolean isItalic = fontInfo.mIsItalic;
         // The list is usually just two fonts big. So iterating over all isn't as bad as it looks.
         // It's biggest for roboto where the size is 12.
-        for (FontInfo font : mFonts) {
+        //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
+        for (int i = 0, n = mFonts.size(); i < n; i++) {
+            FontInfo font = mFonts.get(i);
             if (font.mWeight == weight && font.mIsItalic == isItalic) {
                 return false;
             }
diff --git a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
index 65b65ec..a545283e 100644
--- a/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/graphics/Paint_Delegate.java
@@ -480,8 +480,10 @@
             return;
         }
 
-        delegate.mTextSize = textSize;
-        delegate.updateFontObject();
+        if (delegate.mTextSize != textSize) {
+            delegate.mTextSize = textSize;
+            delegate.updateFontObject();
+        }
     }
 
     @LayoutlibDelegate
@@ -503,8 +505,10 @@
             return;
         }
 
-        delegate.mTextScaleX = scaleX;
-        delegate.updateFontObject();
+        if (delegate.mTextScaleX != scaleX) {
+            delegate.mTextScaleX = scaleX;
+            delegate.updateFontObject();
+        }
     }
 
     @LayoutlibDelegate
@@ -526,8 +530,10 @@
             return;
         }
 
-        delegate.mTextSkewX = skewX;
-        delegate.updateFontObject();
+        if (delegate.mTextSkewX != skewX) {
+            delegate.mTextSkewX = skewX;
+            delegate.updateFontObject();
+        }
     }
 
     @LayoutlibDelegate
@@ -897,9 +903,12 @@
             return 0;
         }
 
-        delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
-        delegate.mNativeTypeface = typeface;
-        delegate.updateFontObject();
+        Typeface_Delegate typefaceDelegate = Typeface_Delegate.getDelegate(typeface);
+        if (delegate.mTypeface != typefaceDelegate || delegate.mNativeTypeface != typeface) {
+            delegate.mTypeface = Typeface_Delegate.getDelegate(typeface);
+            delegate.mNativeTypeface = typeface;
+            delegate.updateFontObject();
+        }
         return typeface;
     }
 
@@ -1214,13 +1223,31 @@
         mCap = paint.mCap;
         mJoin = paint.mJoin;
         mTextAlign = paint.mTextAlign;
-        mTypeface = paint.mTypeface;
-        mNativeTypeface = paint.mNativeTypeface;
+
+        boolean needsFontUpdate = false;
+        if (mTypeface != paint.mTypeface || mNativeTypeface != paint.mNativeTypeface) {
+            mTypeface = paint.mTypeface;
+            mNativeTypeface = paint.mNativeTypeface;
+            needsFontUpdate = true;
+        }
+
+        if (mTextSize != paint.mTextSize) {
+            mTextSize = paint.mTextSize;
+            needsFontUpdate = true;
+        }
+
+        if (mTextScaleX != paint.mTextScaleX) {
+            mTextScaleX = paint.mTextScaleX;
+            needsFontUpdate = true;
+        }
+
+        if (mTextSkewX != paint.mTextSkewX) {
+            mTextSkewX = paint.mTextSkewX;
+            needsFontUpdate = true;
+        }
+
         mStrokeWidth = paint.mStrokeWidth;
         mStrokeMiter = paint.mStrokeMiter;
-        mTextSize = paint.mTextSize;
-        mTextScaleX = paint.mTextScaleX;
-        mTextSkewX = paint.mTextSkewX;
         mXfermode = paint.mXfermode;
         mColorFilter = paint.mColorFilter;
         mShader = paint.mShader;
@@ -1228,7 +1255,10 @@
         mMaskFilter = paint.mMaskFilter;
         mRasterizer = paint.mRasterizer;
         mHintingMode = paint.mHintingMode;
-        updateFontObject();
+
+        if (needsFontUpdate) {
+            updateFontObject();
+        }
     }
 
     private void reset() {
@@ -1264,10 +1294,18 @@
             // Get the fonts from the TypeFace object.
             List<Font> fonts = mTypeface.getFonts(mFontVariant);
 
+            if (fonts.isEmpty()) {
+                mFonts = Collections.emptyList();
+                return;
+            }
+
             // create new font objects as well as FontMetrics, based on the current text size
             // and skew info.
-            ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(fonts.size());
-            for (Font font : fonts) {
+            int nFonts = fonts.size();
+            ArrayList<FontInfo> infoList = new ArrayList<FontInfo>(nFonts);
+            //noinspection ForLoopReplaceableByForEach (avoid iterator instantiation)
+            for (int i = 0; i < nFonts; i++) {
+                Font font = fonts.get(i);
                 if (font == null) {
                     // If the font is null, add null to infoList. When rendering the text, if this
                     // null is reached, a warning will be logged.
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index f1726eb..5db1bde 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -206,7 +206,7 @@
                 File f = new File(value.getValue());
                 if (f.isFile()) {
                     try {
-                        XmlPullParser parser = ParserFactory.create(f);
+                        XmlPullParser parser = ParserFactory.create(f, true);
 
                         BridgeXmlBlockParser bridgeParser = new BridgeXmlBlockParser(
                                 parser, bridgeContext, value.isFramework());
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 778d1a5..0da6bb6 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -338,11 +338,6 @@
     }
 
     @Override
-    public void setAppWillBeHidden(IBinder arg0) throws RemoteException {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
     public void setEventDispatching(boolean arg0) throws RemoteException {
         // TODO Auto-generated method stub
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 689e359..b2dc29a 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -436,7 +436,7 @@
                 // we need to create a pull parser around the layout XML file, and then
                 // give that to our XmlBlockParser
                 try {
-                    XmlPullParser parser = ParserFactory.create(xml);
+                    XmlPullParser parser = ParserFactory.create(xml, true);
 
                     // set the resource ref to have correct view cookies
                     mBridgeInflater.setResourceReference(resource);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index f04654e..e3a19e7 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -65,6 +65,12 @@
     }
 
     @Override
+    public PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
+            throws NameNotFoundException {
+        return null;
+    }
+
+    @Override
     public String[] currentToCanonicalPackageNames(String[] names) {
         return new String[0];
     }
@@ -499,6 +505,11 @@
     }
 
     @Override
+    public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer,int flags,
+            String installerPackageName, int userId) {
+    }
+
+    @Override
     public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
             ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
@@ -516,6 +527,12 @@
     }
 
     @Override
+    public int installExistingPackageAsUser(String packageName, int userId)
+            throws NameNotFoundException {
+        return 0;
+    }
+
+    @Override
     public void verifyPendingInstall(int id, int verificationCode) {
     }
 
@@ -568,6 +585,11 @@
     }
 
     @Override
+    public void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int flags,
+            int userId) {
+    }
+
+    @Override
     public String getInstallerPackageName(String packageName) {
         return null;
     }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java
new file mode 100644
index 0000000..71e7fd2
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/LayoutParserWrapper.java
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2015 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.layoutlib.bridge.impl;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.annotation.Nullable;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.Reader;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * A wrapper around XmlPullParser that can peek forward to inspect if the file is a data-binding
+ * layout and some parts need to be stripped.
+ */
+public class LayoutParserWrapper implements XmlPullParser {
+
+    // Data binding constants.
+    private static final String TAG_LAYOUT = "layout";
+    private static final String TAG_DATA = "data";
+    private static final String DEFAULT = "default=";
+
+    private final XmlPullParser mDelegate;
+
+    // Storage for peeked values.
+    private boolean mPeeked;
+    private int mEventType;
+    private int mDepth;
+    private int mNext;
+    private List<Attribute> mAttributes;
+    private String mText;
+    private String mName;
+
+    // Used to end the document before the actual parser ends.
+    private int mFinalDepth = -1;
+    private boolean mEndNow;
+
+    public LayoutParserWrapper(XmlPullParser delegate) {
+        mDelegate = delegate;
+    }
+
+    public LayoutParserWrapper peekTillLayoutStart() throws IOException, XmlPullParserException {
+        final int STATE_LAYOUT_NOT_STARTED = 0;  // <layout> tag not encountered yet.
+        final int STATE_ROOT_NOT_STARTED = 1;    // the main view root not found yet.
+        final int STATE_INSIDE_DATA = 2;         // START_TAG for <data> found, but not END_TAG.
+
+        int state = STATE_LAYOUT_NOT_STARTED;
+        int dataDepth = -1;    // depth of the <data> tag. Should be two.
+        while (true) {
+            int peekNext = peekNext();
+            switch (peekNext) {
+                case START_TAG:
+                    if (state == STATE_LAYOUT_NOT_STARTED) {
+                        if (mName.equals(TAG_LAYOUT)) {
+                            state = STATE_ROOT_NOT_STARTED;
+                        } else {
+                            return this; // no layout tag in the file.
+                        }
+                    } else if (state == STATE_ROOT_NOT_STARTED) {
+                        if (mName.equals(TAG_DATA)) {
+                            state = STATE_INSIDE_DATA;
+                            dataDepth = mDepth;
+                        } else {
+                            mFinalDepth = mDepth;
+                            return this;
+                        }
+                    }
+                    break;
+                case END_TAG:
+                    if (state == STATE_INSIDE_DATA) {
+                        if (mDepth <= dataDepth) {
+                            state = STATE_ROOT_NOT_STARTED;
+                        }
+                    }
+                    break;
+                case END_DOCUMENT:
+                    // No layout start found.
+                    return this;
+            }
+            // consume the peeked tag.
+            next();
+        }
+    }
+
+    private int peekNext() throws IOException, XmlPullParserException {
+        if (mPeeked) {
+            return mNext;
+        }
+        mEventType = mDelegate.getEventType();
+        mNext = mDelegate.next();
+        if (mEventType == START_TAG) {
+            int count = mDelegate.getAttributeCount();
+            mAttributes = count > 0 ? new ArrayList<Attribute>(count) :
+                    Collections.<Attribute>emptyList();
+            for (int i = 0; i < count; i++) {
+                mAttributes.add(new Attribute(mDelegate.getAttributeNamespace(i),
+                        mDelegate.getAttributeName(i), mDelegate.getAttributeValue(i)));
+            }
+        }
+        mDepth = mDelegate.getDepth();
+        mText = mDelegate.getText();
+        mName = mDelegate.getName();
+        mPeeked = true;
+        return mNext;
+    }
+
+    private void reset() {
+        mAttributes = null;
+        mText = null;
+        mName = null;
+        mPeeked = false;
+    }
+
+    @Override
+    public int next() throws XmlPullParserException, IOException {
+        int returnValue;
+        int depth;
+        if (mPeeked) {
+            returnValue = mNext;
+            depth = mDepth;
+            reset();
+        } else if (mEndNow) {
+            return END_DOCUMENT;
+        } else {
+            returnValue = mDelegate.next();
+            depth = getDepth();
+        }
+        if (returnValue == END_TAG && depth <= mFinalDepth) {
+            mEndNow = true;
+        }
+        return returnValue;
+    }
+
+    @Override
+    public int getEventType() throws XmlPullParserException {
+        return mPeeked ? mEventType : mDelegate.getEventType();
+    }
+
+    @Override
+    public int getDepth() {
+        return mPeeked ? mDepth : mDelegate.getDepth();
+    }
+
+    @Override
+    public String getName() {
+        return mPeeked ? mName : mDelegate.getName();
+    }
+
+    @Override
+    public String getText() {
+        return mPeeked ? mText : mDelegate.getText();
+    }
+
+    @Override
+    public String getAttributeValue(@Nullable String namespace, String name) {
+        String returnValue = null;
+        if (mPeeked) {
+            if (mAttributes == null) {
+                if (mEventType != START_TAG) {
+                    throw new IndexOutOfBoundsException("getAttributeValue() called when not at START_TAG.");
+                } else {
+                    return null;
+                }
+            } else {
+                for (Attribute attribute : mAttributes) {
+                    //noinspection StringEquality for nullness check.
+                    if (attribute.name.equals(name) && (attribute.namespace == namespace ||
+                            attribute.namespace != null && attribute.namespace.equals(namespace))) {
+                        returnValue = attribute.value;
+                        break;
+                    }
+                }
+            }
+        } else {
+            returnValue = mDelegate.getAttributeValue(namespace, name);
+        }
+        // Check if the value is bound via data-binding, if yes get the default value.
+        if (returnValue != null && mFinalDepth >= 0 && returnValue.startsWith("@{")) {
+            // TODO: Improve the detection of default keyword.
+            int i = returnValue.lastIndexOf(DEFAULT);
+            return i > 0 ? returnValue.substring(i + DEFAULT.length(), returnValue.length() - 1)
+                    : null;
+        }
+        return returnValue;
+    }
+
+    private static class Attribute {
+        @Nullable
+        public final String namespace;
+        public final String name;
+        public final String value;
+
+        public Attribute(@Nullable String namespace, String name, String value) {
+            this.namespace = namespace;
+            this.name = name;
+            this.value = value;
+        }
+    }
+
+    // Not affected by peeking.
+
+    @Override
+    public void setFeature(String s, boolean b) throws XmlPullParserException {
+        mDelegate.setFeature(s, b);
+    }
+
+    @Override
+    public void setProperty(String s, Object o) throws XmlPullParserException {
+        mDelegate.setProperty(s, o);
+    }
+
+    @Override
+    public void setInput(InputStream inputStream, String s) throws XmlPullParserException {
+        mDelegate.setInput(inputStream, s);
+    }
+
+    @Override
+    public void setInput(Reader reader) throws XmlPullParserException {
+        mDelegate.setInput(reader);
+    }
+
+    @Override
+    public String getInputEncoding() {
+        return mDelegate.getInputEncoding();
+    }
+
+    @Override
+    public String getNamespace(String s) {
+        return mDelegate.getNamespace(s);
+    }
+
+    @Override
+    public String getPositionDescription() {
+        return mDelegate.getPositionDescription();
+    }
+
+    @Override
+    public int getLineNumber() {
+        return mDelegate.getLineNumber();
+    }
+
+    @Override
+    public String getNamespace() {
+        return mDelegate.getNamespace();
+    }
+
+    @Override
+    public int getColumnNumber() {
+        return mDelegate.getColumnNumber();
+    }
+
+    // -- We don't care much about the methods that follow.
+
+    @Override
+    public void require(int i, String s, String s1) throws XmlPullParserException, IOException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public boolean getFeature(String s) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public void defineEntityReplacementText(String s, String s1) throws XmlPullParserException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public Object getProperty(String s) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public int nextToken() throws XmlPullParserException, IOException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public int getNamespaceCount(int i) throws XmlPullParserException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getNamespacePrefix(int i) throws XmlPullParserException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getNamespaceUri(int i) throws XmlPullParserException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public boolean isWhitespace() throws XmlPullParserException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public char[] getTextCharacters(int[] ints) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getPrefix() {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public boolean isEmptyElementTag() throws XmlPullParserException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public int getAttributeCount() {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getAttributeNamespace(int i) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getAttributeName(int i) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getAttributePrefix(int i) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getAttributeType(int i) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public boolean isAttributeDefault(int i) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String getAttributeValue(int i) {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public String nextText() throws XmlPullParserException, IOException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+
+    @Override
+    public int nextTag() throws XmlPullParserException, IOException {
+        throw new UnsupportedOperationException("Only few parser methods are supported.");
+    }
+}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
index 6e67f59..e273b2c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/ParserFactory.java
@@ -53,24 +53,35 @@
     @NonNull
     public static XmlPullParser create(@NonNull File f)
             throws XmlPullParserException, FileNotFoundException {
-        InputStream stream = new FileInputStream(f);
-        return create(stream, f.getName(), f.length());
+        return create(f, false);
     }
 
+    public static XmlPullParser create(@NonNull File f, boolean isLayout)
+      throws XmlPullParserException, FileNotFoundException {
+        InputStream stream = new FileInputStream(f);
+        return create(stream, f.getName(), f.length(), isLayout);
+    }
     @NonNull
     public static XmlPullParser create(@NonNull InputStream stream, @Nullable String name)
         throws XmlPullParserException {
-        return create(stream, name, -1);
+        return create(stream, name, -1, false);
     }
 
     @NonNull
     private static XmlPullParser create(@NonNull InputStream stream, @Nullable String name,
-            long size) throws XmlPullParserException {
+            long size, boolean isLayout) throws XmlPullParserException {
         XmlPullParser parser = instantiateParser(name);
 
         stream = readAndClose(stream, name, size);
 
         parser.setInput(stream, ENCODING);
+        if (isLayout) {
+            try {
+                return new LayoutParserWrapper(parser).peekTillLayoutStart();
+            } catch (IOException e) {
+                throw new XmlPullParserException(null, parser, e);
+            }
+        }
         return parser;
     }
 
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java
new file mode 100644
index 0000000..2c33862
--- /dev/null
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/impl/LayoutParserWrapperTest.java
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2015 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.layoutlib.bridge.impl;
+
+import org.junit.Test;
+import org.kxml2.io.KXmlParser;
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.StringReader;
+
+import static com.android.SdkConstants.NS_RESOURCES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotSame;
+import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
+import static org.xmlpull.v1.XmlPullParser.END_TAG;
+import static org.xmlpull.v1.XmlPullParser.START_TAG;
+
+
+public class LayoutParserWrapperTest {
+    @Test
+    @SuppressWarnings("StatementWithEmptyBody")  // some for loops need to be empty statements.
+    public void testDataBindingLayout() throws Exception {
+        LayoutParserWrapper parser = getParserFromString(sDataBindingLayout);
+        parser.peekTillLayoutStart();
+        assertEquals("Expected START_TAG", START_TAG, parser.next());
+        assertEquals("RelativeLayout", parser.getName());
+        for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT;
+             next = parser.next());
+        assertEquals("Expected START_TAG", START_TAG, parser.getEventType());
+        assertEquals("TextView", parser.getName());
+        assertEquals("layout_width incorrect for first text view.", "wrap_content",
+                parser.getAttributeValue(NS_RESOURCES, "layout_width"));
+        // Ensure that data-binding part is stripped.
+        assertEquals("Bound attribute android:text incorrect", "World",
+                parser.getAttributeValue(NS_RESOURCES, "text"));
+        assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first",
+                parser.getAttributeValue(NS_RESOURCES, "id"));
+        for (int next = parser.next();
+             (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT;
+             next = parser.next());
+        assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType());
+        assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next());
+    }
+
+    @Test
+    @SuppressWarnings("StatementWithEmptyBody")
+    public void testNonDataBindingLayout() throws Exception {
+        LayoutParserWrapper parser = getParserFromString(sNonDataBindingLayout);
+        parser.peekTillLayoutStart();
+        assertEquals("Expected START_TAG", START_TAG, parser.next());
+        assertEquals("RelativeLayout", parser.getName());
+        for (int next = parser.next(); next != START_TAG && next != END_DOCUMENT;
+             next = parser.next());
+        assertEquals("Expected START_TAG", START_TAG, parser.getEventType());
+        assertEquals("TextView", parser.getName());
+        assertEquals("layout_width incorrect for first text view.", "wrap_content",
+                parser.getAttributeValue(NS_RESOURCES, "layout_width"));
+        // Ensure that value isn't modified.
+        assertEquals("Bound attribute android:text incorrect", "@{user.firstName,default=World}",
+                parser.getAttributeValue(NS_RESOURCES, "text"));
+        assertEquals("resource attribute 'id' for first text view incorrect.", "@+id/first",
+                parser.getAttributeValue(NS_RESOURCES, "id"));
+        for (int next = parser.next();
+             (next != END_TAG || !"RelativeLayout".equals(parser.getName())) && next != END_DOCUMENT;
+             next = parser.next());
+        assertNotSame("Unexpected end of document", END_DOCUMENT, parser.getEventType());
+        assertEquals("Document didn't end when expected.", END_DOCUMENT, parser.next());
+    }
+
+    private static LayoutParserWrapper getParserFromString(String layoutContent) throws
+            XmlPullParserException {
+        XmlPullParser parser = new KXmlParser();
+        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
+        parser.setInput(new StringReader(layoutContent));
+        return new LayoutParserWrapper(parser);
+    }
+
+    private static final String sDataBindingLayout =
+            //language=XML
+            "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n" +
+                    "<layout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                    "        xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" +
+                    "        xmlns:tools=\"http://schemas.android.com/tools\"\n" +
+                    "        tools:context=\".MainActivity\"\n" +
+                    "        tools:showIn=\"@layout/activity_main\">\n" +
+                    "\n" +
+                    "    <data>\n" +
+                    "\n" +
+                    "        <variable\n" +
+                    "            name=\"user\"\n" +
+                    "            type=\"com.example.User\" />\n" +
+                    "        <variable\n" +
+                    "            name=\"activity\"\n" +
+                    "            type=\"com.example.MainActivity\" />\n" +
+                    "    </data>\n" +
+                    "\n" +
+                    "    <RelativeLayout\n" +
+                    "        android:layout_width=\"match_parent\"\n" +
+                    "        android:layout_height=\"match_parent\"\n" +
+                    "        android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" +
+                    "        android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" +
+                    "        android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" +
+                    "        android:paddingTop=\"@dimen/activity_vertical_margin\"\n" +
+                    "        app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" +
+                    "    >\n" +
+                    "\n" +
+                    "        <TextView\n" +
+                    "            android:id=\"@+id/first\"\n" +
+                    "            android:layout_width=\"wrap_content\"\n" +
+                    "            android:layout_alignParentStart=\"true\"\n" +
+                    "            android:layout_alignParentLeft=\"true\"\n" +
+                    "            android:layout_height=\"wrap_content\"\n" +
+                    "            android:text=\"@{user.firstName,default=World}\" />\n" +
+                    "\n" +
+                    "        <TextView\n" +
+                    "            android:id=\"@+id/last\"\n" +
+                    "            android:layout_width=\"wrap_content\"\n" +
+                    "            android:layout_height=\"wrap_content\"\n" +
+                    "            android:layout_toEndOf=\"@id/first\"\n" +
+                    "            android:layout_toRightOf=\"@id/first\"\n" +
+                    "            android:text=\"@{user.lastName,default=Hello}\" />\n" +
+                    "\n" +
+                    "        <Button\n" +
+                    "            android:layout_width=\"wrap_content\"\n" +
+                    "            android:layout_height=\"wrap_content\"\n" +
+                    "            android:layout_below=\"@id/last\"\n" +
+                    "            android:text=\"Submit\"\n" +
+                    "            android:onClick=\"@{activity.onClick}\"/>\n" +
+                    "    </RelativeLayout>\n" +
+                    "</layout>";
+
+    private static final String sNonDataBindingLayout =
+            //language=XML
+            "<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n" +
+                    "    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n" +
+                    "    android:layout_width=\"match_parent\"\n" +
+                    "    android:layout_height=\"match_parent\"\n" +
+                    "    android:paddingBottom=\"@dimen/activity_vertical_margin\"\n" +
+                    "    android:paddingLeft=\"@dimen/activity_horizontal_margin\"\n" +
+                    "    android:paddingRight=\"@dimen/activity_horizontal_margin\"\n" +
+                    "    android:paddingTop=\"@dimen/activity_vertical_margin\"\n" +
+                    "    app:layout_behavior=\"@string/appbar_scrolling_view_behavior\"\n" +
+                    ">\n" +
+                    "\n" +
+                    "    <TextView\n" +
+                    "        android:id=\"@+id/first\"\n" +
+                    "        android:layout_width=\"wrap_content\"\n" +
+                    "        android:layout_alignParentStart=\"true\"\n" +
+                    "        android:layout_alignParentLeft=\"true\"\n" +
+                    "        android:layout_height=\"wrap_content\"\n" +
+                    "        android:text=\"@{user.firstName,default=World}\" />\n" +
+                    "\n" +
+                    "    <TextView\n" +
+                    "        android:id=\"@+id/last\"\n" +
+                    "        android:layout_width=\"wrap_content\"\n" +
+                    "        android:layout_height=\"wrap_content\"\n" +
+                    "        android:layout_toEndOf=\"@id/first\"\n" +
+                    "        android:layout_toRightOf=\"@id/first\"\n" +
+                    "        android:text=\"@{user.lastName,default=Hello}\" />\n" +
+                    "\n" +
+                    "    <Button\n" +
+                    "        android:layout_width=\"wrap_content\"\n" +
+                    "        android:layout_height=\"wrap_content\"\n" +
+                    "        android:layout_below=\"@id/last\"\n" +
+                    "        android:text=\"Submit\"\n" +
+                    "        android:onClick=\"@{activity.onClick}\"/>\n" +
+                    "</RelativeLayout>";
+}
diff --git a/wifi/java/android/net/wifi/IWifiManager.aidl b/wifi/java/android/net/wifi/IWifiManager.aidl
index 0d95b38..23be8e0 100644
--- a/wifi/java/android/net/wifi/IWifiManager.aidl
+++ b/wifi/java/android/net/wifi/IWifiManager.aidl
@@ -23,6 +23,7 @@
 import android.net.wifi.ScanSettings;
 import android.net.wifi.WifiChannel;
 import android.net.wifi.ScanResult;
+import android.net.wifi.ScanInfo;
 import android.net.wifi.WifiConnectionStatistics;
 import android.net.wifi.WifiActivityEnergyInfo;
 import android.net.Network;
@@ -70,6 +71,10 @@
 
     void disconnect();
 
+    List<ScanInfo> getScanInfos(String callingPackage);
+
+    void setOsuSelection(int osuID);
+
     void reconnect();
 
     void reassociate();
diff --git a/packages/SystemUI/res/values-sw600dp-port/dimens.xml b/wifi/java/android/net/wifi/ScanInfo.aidl
similarity index 69%
rename from packages/SystemUI/res/values-sw600dp-port/dimens.xml
rename to wifi/java/android/net/wifi/ScanInfo.aidl
index 7dc91d1..18ae508 100644
--- a/packages/SystemUI/res/values-sw600dp-port/dimens.xml
+++ b/wifi/java/android/net/wifi/ScanInfo.aidl
@@ -1,6 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
- * Copyright (c) 2012, The Android Open Source Project
+/**
+ * Copyright (c) 2015, The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,9 +12,8 @@
  * 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>
-    <!-- Recent Applications parameters -->
-    <dimen name="status_bar_recents_app_label_width">140dip</dimen>
-</resources>
+ */
+
+package android.net.wifi;
+
+parcelable ScanInfo;
diff --git a/wifi/java/android/net/wifi/ScanInfo.java b/wifi/java/android/net/wifi/ScanInfo.java
new file mode 100644
index 0000000..39186fa
--- /dev/null
+++ b/wifi/java/android/net/wifi/ScanInfo.java
@@ -0,0 +1,189 @@
+package android.net.wifi;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+public class ScanInfo implements Parcelable {
+    private final ScanResult mScanResult;
+
+    private final long mBSSID;          // The BSSID of the best AP with an SSID matching the OSU
+    private final int mRSSI;            // RSSI of the AP with BSSID
+    private final String mSSID;         // The SSID to connect to for an OSU connection.
+    private final String mName;
+    private final String mServiceDescription;
+    private final String mIconType;
+    private final byte[] mIconData;
+    private final int mOSUIdentity;
+
+    public ScanInfo(ScanResult scanResult) {
+        mScanResult = scanResult;
+
+        mBSSID = -1;
+        mRSSI = -1;
+        mSSID = null;
+        mName = null;
+        mServiceDescription = null;
+        mIconType = null;
+        mIconData = null;
+        mOSUIdentity = -1;
+    }
+
+    public ScanInfo(long BSSID, int rssi, String SSID, String name, String serviceDescription,
+                    String iconType, byte[] iconData, int OSUIdentity) {
+        mBSSID = BSSID;
+        mRSSI = rssi;
+        mSSID = SSID;
+        mName = name;
+        mServiceDescription = serviceDescription;
+        mIconType = iconType;
+        mIconData = iconData;
+        mOSUIdentity = OSUIdentity;
+
+        mScanResult = null;
+    }
+
+    /**
+     * Get the scan result of this ScanInfo.
+     * @return The ScanResult, if this ScanInfo contains a one. If the ScanInfo contains
+     * OSU information getScanResult will return null.
+     */
+    public ScanResult getScanResult() {
+        return mScanResult;
+    }
+
+    /**
+     * OSU only: The BSSID of the AP who advertises the OSU SSID. This value is not guaranteed to
+     * be correct; In the somewhat unlikely case that multiple APs advertise OSU SSIDs that matches
+     * an OSU information element returned through ANQP and one of those is not related to an OSU
+     * there is a (slight) risk that the BSSID is for a "spoof" OSU.
+     * The matching algorithm that produces the ScanInfo objects makes a best effort to get the
+     * matching right though and since it is (a) fair to assume that the OSU SSID resides on the
+     * same AP as the one advertising the OSU information, and (b) BSSIDs for multi-SSID APs are
+     * typically adjacent to each other, matching will prefer the BSSID closest to the advertising
+     * APs BSSID if multiple SSIDs match.
+     * @return The BSSID.
+     */
+    public long getBssid() {
+        return mBSSID;
+    }
+
+    /**
+     * OSU only.
+     * @return The signal level of the AP associated with the BSSID from getBSSID.
+     */
+    public int getRssi() {
+        return mRSSI;
+    }
+
+    /**
+     * OSU only.
+     * @return The SSID of the AP to which to associate to establish an OSU connection.
+     */
+    public String getSsid() {
+        return mSSID;
+    }
+
+    /**
+     * OSU only.
+     * @return The name of the Service Provider of the OSU.
+     */
+    public String getName() {
+        return mName;
+    }
+
+    /**
+     * OSU only.
+     * @return The service description of the OSU.
+     */
+    public String getServiceDescription() {
+        return mServiceDescription;
+    }
+
+    /**
+     * OSU only.
+     * Get the type of icon that icon data represents, e.g. JPG, PNG etc. This field is formatted
+     * using standard MIME encodings per RFC-4288 and IANA MIME media types.
+     * @return The icon type in icon data.
+     */
+    public String getIconType() {
+        return mIconType;
+    }
+
+    /**
+     * OSU only.
+     * @return The binary data of the icon.
+     */
+    public byte[] getIconData() {
+        return mIconData;
+    }
+
+    /**
+     * OSU only.
+     * @return a unique identity for the OSU. This value is generated by the framework and should
+     * be used to uniquely identify a specific OSU. Please note that values may be reused after
+     * a very long time-span (in any normal scenario, likely years) and implementations should make
+     * sure to not rely on any long term persisted values.
+     */
+    public int getOsuIdentity() {
+        return mOSUIdentity;
+    }
+
+    private static final int ScanResultMarker = 0;
+    private static final int OSUMarker = 1;
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface {@hide} */
+    public static final Creator<ScanInfo> CREATOR =
+            new Creator<ScanInfo>() {
+                @Override
+                public ScanInfo createFromParcel(Parcel source) {
+                    int marker = source.readInt();
+                    if (marker == ScanResultMarker) {
+                        return new ScanInfo(ScanResult.CREATOR.createFromParcel(source));
+                    }
+                    else if (marker == OSUMarker) {
+                        return new ScanInfo(
+                                source.readLong(),
+                                source.readInt(),
+                                source.readString(),
+                                source.readString(),
+                                source.readString(),
+                                source.readString(),
+                                source.createByteArray(),
+                                source.readInt()
+                                );
+                    }
+                    else {
+                        throw new RuntimeException("Bad ScanInfo data");
+                    }
+                }
+
+                @Override
+                public ScanInfo[] newArray(int size) {
+                    return new ScanInfo[0];
+                }
+            };
+
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        if (mScanResult != null) {
+            dest.writeInt(ScanResultMarker);
+            mScanResult.writeToParcel(dest, flags);
+            return;
+        }
+
+        dest.writeInt(OSUMarker);
+        dest.writeLong(mBSSID);
+        dest.writeInt(mRSSI);
+        dest.writeString(mSSID);
+        dest.writeString(mName);
+        dest.writeString(mServiceDescription);
+        dest.writeString(mIconType);
+        dest.writeByteArray(mIconData);
+        dest.writeInt(mOSUIdentity);
+    }
+}
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index cf88df4..ff8d6d4d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1315,6 +1315,30 @@
     }
 
     /**
+     * An augmented version of getScanResults that returns ScanResults as well as OSU information
+     * wrapped in ScanInfo objects.
+     * @return
+     */
+    public List<ScanInfo> getScanInfos() {
+        try {
+            return mService.getScanInfos(mContext.getOpPackageName());
+        } catch (RemoteException e) {
+            return null;
+        }
+    }
+
+    /**
+     * Notify the OSU framework about the currently selected OSU.
+     * @param osuID The OSU ID from ScanInfo.getOsuIdentity()
+     */
+    public void setOsuSelection(int osuID) {
+        try {
+            mService.setOsuSelection(osuID);
+        } catch (RemoteException e) {
+        }
+    }
+
+    /**
      * Check if scanning is always available.
      *
      * If this return {@code true}, apps can issue {@link #startScan} and fetch scan results