Merge "Fixed NullPointerException in SystemUI"
diff --git a/Android.mk b/Android.mk
index 52ed634..ad164e20 100644
--- a/Android.mk
+++ b/Android.mk
@@ -419,6 +419,7 @@
 	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
+	telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index f13601e..0f90986 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -2625,6 +2625,7 @@
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+    method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
@@ -2683,6 +2684,18 @@
     method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
   }
 
+  public static final class AccessibilityService.SoftKeyboardController {
+    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+    method public int getShowMode();
+    method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public boolean setShowMode(int);
+  }
+
+  public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+    method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+  }
+
   public class AccessibilityServiceInfo implements android.os.Parcelable {
     ctor public AccessibilityServiceInfo();
     method public static java.lang.String capabilityToString(int);
@@ -4642,6 +4655,7 @@
     method public android.content.Context getContext();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
+    method public android.app.UiAutomation getUiAutomation(int);
     method public boolean invokeContextMenuAction(android.app.Activity, int, int);
     method public boolean invokeMenuActionSync(android.app.Activity, int, int);
     method public boolean isProfiling();
@@ -5538,6 +5552,7 @@
   public final class UiAutomation {
     method public void clearWindowAnimationFrameStats();
     method public boolean clearWindowContentFrameStats(int);
+    method public void destroy();
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
     method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5554,6 +5569,7 @@
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public android.graphics.Bitmap takeScreenshot();
     method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+    field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
     field public static final int ROTATION_FREEZE_0 = 0; // 0x0
     field public static final int ROTATION_FREEZE_180 = 2; // 0x2
     field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -5821,6 +5837,7 @@
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
+    method public java.lang.String getOrganizationName(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -5890,6 +5907,7 @@
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setOrganizationColor(android.content.ComponentName, int);
+    method public void setOrganizationName(android.content.ComponentName, java.lang.String);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -19871,6 +19889,7 @@
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public int getSampleRate();
     method public int getState();
+    method public int getTimestamp(android.media.AudioTimestamp, int);
     method public int read(byte[], int, int);
     method public int read(byte[], int, int, int);
     method public int read(short[], int, int);
@@ -19942,6 +19961,8 @@
 
   public final class AudioTimestamp {
     ctor public AudioTimestamp();
+    field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+    field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
     field public long framePosition;
     field public long nanoTime;
   }
@@ -22496,6 +22517,7 @@
     method public void setRatingType(int);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
@@ -22574,6 +22596,7 @@
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+    field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22890,7 +22913,7 @@
     method public void onInputAdded(java.lang.String);
     method public void onInputRemoved(java.lang.String);
     method public void onInputStateChanged(java.lang.String, int);
-    method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+    method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
@@ -22898,7 +22921,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
     method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
-    method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+    method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
     field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
   }
@@ -28536,6 +28559,10 @@
     field public static final int OPEN = 32; // 0x20
   }
 
+  public class FileUriExposedException extends java.lang.RuntimeException {
+    ctor public FileUriExposedException(java.lang.String);
+  }
+
   public class Handler {
     ctor public Handler();
     ctor public Handler(android.os.Handler.Callback);
@@ -29127,6 +29154,7 @@
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+    method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
     method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
     method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -51301,6 +51329,9 @@
   public abstract class Inherited implements java.lang.annotation.Annotation {
   }
 
+  public abstract class Repeatable implements java.lang.annotation.Annotation {
+  }
+
   public abstract class Retention implements java.lang.annotation.Annotation {
   }
 
diff --git a/api/system-current.txt b/api/system-current.txt
index 0d33503..1091ff1 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -2727,6 +2727,7 @@
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+    method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
@@ -2785,6 +2786,18 @@
     method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
   }
 
+  public static final class AccessibilityService.SoftKeyboardController {
+    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+    method public int getShowMode();
+    method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public boolean setShowMode(int);
+  }
+
+  public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+    method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+  }
+
   public class AccessibilityServiceInfo implements android.os.Parcelable {
     ctor public AccessibilityServiceInfo();
     method public static java.lang.String capabilityToString(int);
@@ -4774,6 +4787,7 @@
     method public android.content.Context getContext();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
+    method public android.app.UiAutomation getUiAutomation(int);
     method public boolean invokeContextMenuAction(android.app.Activity, int, int);
     method public boolean invokeMenuActionSync(android.app.Activity, int, int);
     method public boolean isProfiling();
@@ -5670,6 +5684,7 @@
   public final class UiAutomation {
     method public void clearWindowAnimationFrameStats();
     method public boolean clearWindowContentFrameStats(int);
+    method public void destroy();
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
     method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5686,6 +5701,7 @@
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public android.graphics.Bitmap takeScreenshot();
     method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+    field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
     field public static final int ROTATION_FREEZE_0 = 0; // 0x0
     field public static final int ROTATION_FREEZE_180 = 2; // 0x2
     field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -5961,6 +5977,7 @@
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
+    method public java.lang.String getOrganizationName(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -6036,6 +6053,7 @@
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setOrganizationColor(android.content.ComponentName, int);
+    method public void setOrganizationName(android.content.ComponentName, java.lang.String);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -21137,6 +21155,7 @@
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public int getSampleRate();
     method public int getState();
+    method public int getTimestamp(android.media.AudioTimestamp, int);
     method public int read(byte[], int, int);
     method public int read(byte[], int, int, int);
     method public int read(short[], int, int);
@@ -21210,6 +21229,8 @@
 
   public final class AudioTimestamp {
     ctor public AudioTimestamp();
+    field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+    field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
     field public long framePosition;
     field public long nanoTime;
   }
@@ -23837,6 +23858,7 @@
     method public void setRatingType(int);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
@@ -23915,6 +23937,7 @@
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+    field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
@@ -24405,7 +24428,7 @@
     method public void onInputRemoved(java.lang.String);
     method public void onInputStateChanged(java.lang.String, int);
     method public void onInputUpdated(java.lang.String);
-    method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+    method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
@@ -24417,7 +24440,7 @@
     method public java.lang.String onHardwareRemoved(android.media.tv.TvInputHardwareInfo);
     method public android.media.tv.TvInputInfo onHdmiDeviceAdded(android.hardware.hdmi.HdmiDeviceInfo);
     method public java.lang.String onHdmiDeviceRemoved(android.hardware.hdmi.HdmiDeviceInfo);
-    method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+    method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
     field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
   }
@@ -30564,6 +30587,10 @@
     field public static final int OPEN = 32; // 0x20
   }
 
+  public class FileUriExposedException extends java.lang.RuntimeException {
+    ctor public FileUriExposedException(java.lang.String);
+  }
+
   public class Handler {
     ctor public Handler();
     ctor public Handler(android.os.Handler.Callback);
@@ -31163,6 +31190,7 @@
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+    method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
     method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
     method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -54055,6 +54083,9 @@
   public abstract class Inherited implements java.lang.annotation.Annotation {
   }
 
+  public abstract class Repeatable implements java.lang.annotation.Annotation {
+  }
+
   public abstract class Retention implements java.lang.annotation.Annotation {
   }
 
diff --git a/api/test-current.txt b/api/test-current.txt
index 48fd6f0..2c5cc3a 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -2625,6 +2625,7 @@
     method public final android.accessibilityservice.AccessibilityService.MagnificationController getMagnificationController();
     method public android.view.accessibility.AccessibilityNodeInfo getRootInActiveWindow();
     method public final android.accessibilityservice.AccessibilityServiceInfo getServiceInfo();
+    method public final android.accessibilityservice.AccessibilityService.SoftKeyboardController getSoftKeyboardController();
     method public java.util.List<android.view.accessibility.AccessibilityWindowInfo> getWindows();
     method public abstract void onAccessibilityEvent(android.view.accessibility.AccessibilityEvent);
     method public final android.os.IBinder onBind(android.content.Intent);
@@ -2683,6 +2684,18 @@
     method public abstract void onMagnificationChanged(android.accessibilityservice.AccessibilityService.MagnificationController, android.graphics.Region, float, float, float);
   }
 
+  public static final class AccessibilityService.SoftKeyboardController {
+    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public void addOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener, android.os.Handler);
+    method public int getShowMode();
+    method public boolean removeOnShowModeChangedListener(android.accessibilityservice.AccessibilityService.SoftKeyboardController.OnShowModeChangedListener);
+    method public boolean setShowMode(int);
+  }
+
+  public static abstract interface AccessibilityService.SoftKeyboardController.OnShowModeChangedListener {
+    method public abstract void onShowModeChanged(android.accessibilityservice.AccessibilityService.SoftKeyboardController, int);
+  }
+
   public class AccessibilityServiceInfo implements android.os.Parcelable {
     ctor public AccessibilityServiceInfo();
     method public static java.lang.String capabilityToString(int);
@@ -4642,6 +4655,7 @@
     method public android.content.Context getContext();
     method public android.content.Context getTargetContext();
     method public android.app.UiAutomation getUiAutomation();
+    method public android.app.UiAutomation getUiAutomation(int);
     method public boolean invokeContextMenuAction(android.app.Activity, int, int);
     method public boolean invokeMenuActionSync(android.app.Activity, int, int);
     method public boolean isProfiling();
@@ -5538,6 +5552,7 @@
   public final class UiAutomation {
     method public void clearWindowAnimationFrameStats();
     method public boolean clearWindowContentFrameStats(int);
+    method public void destroy();
     method public android.view.accessibility.AccessibilityEvent executeAndWaitForEvent(java.lang.Runnable, android.app.UiAutomation.AccessibilityEventFilter, long) throws java.util.concurrent.TimeoutException;
     method public android.os.ParcelFileDescriptor executeShellCommand(java.lang.String);
     method public android.view.accessibility.AccessibilityNodeInfo findFocus(int);
@@ -5556,6 +5571,7 @@
     method public final void setServiceInfo(android.accessibilityservice.AccessibilityServiceInfo);
     method public android.graphics.Bitmap takeScreenshot();
     method public void waitForIdle(long, long) throws java.util.concurrent.TimeoutException;
+    field public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 1; // 0x1
     field public static final int ROTATION_FREEZE_0 = 0; // 0x0
     field public static final int ROTATION_FREEZE_180 = 2; // 0x2
     field public static final int ROTATION_FREEZE_270 = 3; // 0x3
@@ -5823,6 +5839,7 @@
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
+    method public java.lang.String getOrganizationName(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
     method public android.app.admin.DevicePolicyManager getParentProfileInstance(android.content.ComponentName);
     method public long getPasswordExpiration(android.content.ComponentName);
@@ -5892,6 +5909,7 @@
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
     method public void setOrganizationColor(android.content.ComponentName, int);
+    method public void setOrganizationName(android.content.ComponentName, java.lang.String);
     method public boolean setPackageSuspended(android.content.ComponentName, java.lang.String, boolean);
     method public void setPasswordExpirationTimeout(android.content.ComponentName, long);
     method public void setPasswordHistoryLength(android.content.ComponentName, int);
@@ -19880,6 +19898,7 @@
     method public android.media.AudioDeviceInfo getRoutedDevice();
     method public int getSampleRate();
     method public int getState();
+    method public int getTimestamp(android.media.AudioTimestamp, int);
     method public int read(byte[], int, int);
     method public int read(byte[], int, int, int);
     method public int read(short[], int, int);
@@ -19951,6 +19970,8 @@
 
   public final class AudioTimestamp {
     ctor public AudioTimestamp();
+    field public static final int TIMEBASE_BOOTTIME = 1; // 0x1
+    field public static final int TIMEBASE_MONOTONIC = 0; // 0x0
     field public long framePosition;
     field public long nanoTime;
   }
@@ -22505,6 +22526,7 @@
     method public void setRatingType(int);
     method public void setSessionActivity(android.app.PendingIntent);
     field public static final int FLAG_HANDLES_MEDIA_BUTTONS = 1; // 0x1
+    field public static final int FLAG_HANDLES_PREPARE_ONLY = 4; // 0x4
     field public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 2; // 0x2
   }
 
@@ -22583,6 +22605,7 @@
     field public static final long ACTION_SKIP_TO_QUEUE_ITEM = 4096L; // 0x1000L
     field public static final long ACTION_STOP = 1L; // 0x1L
     field public static final android.os.Parcelable.Creator<android.media.session.PlaybackState> CREATOR;
+    field public static final java.lang.String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
     field public static final long PLAYBACK_POSITION_UNKNOWN = -1L; // 0xffffffffffffffffL
     field public static final int STATE_BUFFERING = 6; // 0x6
     field public static final int STATE_CONNECTING = 8; // 0x8
@@ -22899,7 +22922,7 @@
     method public void onInputAdded(java.lang.String);
     method public void onInputRemoved(java.lang.String);
     method public void onInputStateChanged(java.lang.String, int);
-    method public void onTvInputInfoChanged(java.lang.String, android.media.tv.TvInputInfo);
+    method public void onTvInputInfoChanged(android.media.tv.TvInputInfo);
   }
 
   public abstract class TvInputService extends android.app.Service {
@@ -22907,7 +22930,7 @@
     method public final android.os.IBinder onBind(android.content.Intent);
     method public android.media.tv.TvInputService.RecordingSession onCreateRecordingSession(java.lang.String);
     method public abstract android.media.tv.TvInputService.Session onCreateSession(java.lang.String);
-    method public final void setTvInputInfo(java.lang.String, android.media.tv.TvInputInfo);
+    method public static final void setTvInputInfo(android.content.Context, android.media.tv.TvInputInfo);
     field public static final java.lang.String SERVICE_INTERFACE = "android.media.tv.TvInputService";
     field public static final java.lang.String SERVICE_META_DATA = "android.media.tv.input";
   }
@@ -28545,6 +28568,10 @@
     field public static final int OPEN = 32; // 0x20
   }
 
+  public class FileUriExposedException extends java.lang.RuntimeException {
+    ctor public FileUriExposedException(java.lang.String);
+  }
+
   public class Handler {
     ctor public Handler();
     ctor public Handler(android.os.Handler.Callback);
@@ -29136,6 +29163,7 @@
     method public android.os.StrictMode.VmPolicy.Builder detectLeakedSqlLiteObjects();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeath();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnCleartextNetwork();
+    method public android.os.StrictMode.VmPolicy.Builder penaltyDeathOnFileUriExposure();
     method public android.os.StrictMode.VmPolicy.Builder penaltyDropBox();
     method public android.os.StrictMode.VmPolicy.Builder penaltyLog();
     method public android.os.StrictMode.VmPolicy.Builder setClassInstanceLimit(java.lang.Class, int);
@@ -51318,6 +51346,9 @@
   public abstract class Inherited implements java.lang.annotation.Annotation {
   }
 
+  public abstract class Repeatable implements java.lang.annotation.Annotation {
+  }
+
   public abstract class Retention implements java.lang.annotation.Annotation {
   }
 
diff --git a/core/java/android/accessibilityservice/AccessibilityService.java b/core/java/android/accessibilityservice/AccessibilityService.java
index be93926..c96cca2 100644
--- a/core/java/android/accessibilityservice/AccessibilityService.java
+++ b/core/java/android/accessibilityservice/AccessibilityService.java
@@ -17,6 +17,7 @@
 package android.accessibilityservice;
 
 import android.accessibilityservice.GestureDescription.MotionEventGenerator;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.Service;
@@ -29,6 +30,7 @@
 import android.os.Looper;
 import android.os.Message;
 import android.os.RemoteException;
+import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Pair;
@@ -46,6 +48,8 @@
 import com.android.internal.os.HandlerCaller;
 import com.android.internal.os.SomeArgs;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.List;
 
 /**
@@ -363,9 +367,26 @@
         public boolean onKeyEvent(KeyEvent event);
         public void onMagnificationChanged(@NonNull Region region,
                 float scale, float centerX, float centerY);
+        public void onSoftKeyboardShowModeChanged(int showMode);
         public void onPerformGestureResult(int sequence, boolean completedSuccessfully);
     }
 
+    /**
+     * Annotations for Soft Keyboard show modes so tools can catch invalid show modes.
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({SHOW_MODE_AUTO, SHOW_MODE_HIDDEN})
+    public @interface SoftKeyboardShowMode {};
+    /**
+     * @hide
+     */
+    public static final int SHOW_MODE_AUTO = 0;
+    /**
+     * @hide
+     */
+    public static final int SHOW_MODE_HIDDEN = 1;
+
     private int mConnectionId;
 
     private AccessibilityServiceInfo mInfo;
@@ -375,6 +396,7 @@
     private WindowManager mWindowManager;
 
     private MagnificationController mMagnificationController;
+    private SoftKeyboardController mSoftKeyboardController;
 
     private int mGestureStatusCallbackSequence;
 
@@ -563,10 +585,12 @@
      */
     @NonNull
     public final MagnificationController getMagnificationController() {
-        if (mMagnificationController == null) {
-            mMagnificationController = new MagnificationController(this);
+        synchronized (mLock) {
+            if (mMagnificationController == null) {
+                mMagnificationController = new MagnificationController(this, mLock);
+            }
+            return mMagnificationController;
         }
-        return mMagnificationController;
     }
 
     /**
@@ -670,17 +694,21 @@
          * first magnification listener.
          */
         private ArrayMap<OnMagnificationChangedListener, Handler> mListeners;
+        private final Object mLock;
 
-        MagnificationController(@NonNull AccessibilityService service) {
+        MagnificationController(@NonNull AccessibilityService service, @NonNull Object lock) {
             mService = service;
+            mLock = lock;
         }
 
         /**
          * Called when the service is connected.
          */
         void onServiceConnected() {
-            if (mListeners != null && !mListeners.isEmpty()) {
-                setMagnificationCallbackEnabled(true);
+            synchronized (mLock) {
+                if (mListeners != null && !mListeners.isEmpty()) {
+                    setMagnificationCallbackEnabled(true);
+                }
             }
         }
 
@@ -707,17 +735,19 @@
          */
         public void addListener(@NonNull OnMagnificationChangedListener listener,
                 @Nullable Handler handler) {
-            if (mListeners == null) {
-                mListeners = new ArrayMap<>();
-            }
+            synchronized (mLock) {
+                if (mListeners == null) {
+                    mListeners = new ArrayMap<>();
+                }
 
-            final boolean shouldEnableCallback = mListeners.isEmpty();
-            mListeners.put(listener, handler);
+                final boolean shouldEnableCallback = mListeners.isEmpty();
+                mListeners.put(listener, handler);
 
-            if (shouldEnableCallback) {
-                // This may fail if the service is not connected yet, but if we
-                // still have listeners when it connects then we can try again.
-                setMagnificationCallbackEnabled(true);
+                if (shouldEnableCallback) {
+                    // This may fail if the service is not connected yet, but if we
+                    // still have listeners when it connects then we can try again.
+                    setMagnificationCallbackEnabled(true);
+                }
             }
         }
 
@@ -734,19 +764,21 @@
                 return false;
             }
 
-            final int keyIndex = mListeners.indexOfKey(listener);
-            final boolean hasKey = keyIndex >= 0;
-            if (hasKey) {
-                mListeners.removeAt(keyIndex);
-            }
+            synchronized (mLock) {
+                final int keyIndex = mListeners.indexOfKey(listener);
+                final boolean hasKey = keyIndex >= 0;
+                if (hasKey) {
+                    mListeners.removeAt(keyIndex);
+                }
 
-            if (hasKey && mListeners.isEmpty()) {
-                // We just removed the last listener, so we don't need
-                // callbacks from the service anymore.
-                setMagnificationCallbackEnabled(false);
-            }
+                if (hasKey && mListeners.isEmpty()) {
+                    // We just removed the last listener, so we don't need
+                    // callbacks from the service anymore.
+                    setMagnificationCallbackEnabled(false);
+                }
 
-            return hasKey;
+                return hasKey;
+            }
         }
 
         private void setMagnificationCallbackEnabled(boolean enabled) {
@@ -768,17 +800,19 @@
          */
         void dispatchMagnificationChanged(final @NonNull Region region, final float scale,
                 final float centerX, final float centerY) {
-            if (mListeners == null || mListeners.isEmpty()) {
-                Slog.d(LOG_TAG, "Received magnification changed "
-                        + "callback with no listeners registered!");
-                setMagnificationCallbackEnabled(false);
-                return;
-            }
+            final ArrayMap<OnMagnificationChangedListener, Handler> entries;
+            synchronized (mLock) {
+                if (mListeners == null || mListeners.isEmpty()) {
+                    Slog.d(LOG_TAG, "Received magnification changed "
+                            + "callback with no listeners registered!");
+                    setMagnificationCallbackEnabled(false);
+                    return;
+                }
 
-            // Listeners may remove themselves. Perform a shallow copy to avoid
-            // concurrent modification.
-            final ArrayMap<OnMagnificationChangedListener, Handler> entries =
-                    new ArrayMap<>(mListeners);
+                // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+                // modification.
+                entries = new ArrayMap<>(mListeners);
+            }
 
             for (int i = 0, count = entries.size(); i < count; i++) {
                 final OnMagnificationChangedListener listener = entries.keyAt(i);
@@ -1011,6 +1045,243 @@
     }
 
     /**
+     * Returns the soft keyboard controller, which may be used to query and modify the soft keyboard
+     * show mode.
+     *
+     * @return the soft keyboard controller
+     */
+    @NonNull
+    public final SoftKeyboardController getSoftKeyboardController() {
+        synchronized (mLock) {
+            if (mSoftKeyboardController == null) {
+                mSoftKeyboardController = new SoftKeyboardController(this, mLock);
+            }
+            return mSoftKeyboardController;
+        }
+    }
+
+    private void onSoftKeyboardShowModeChanged(int showMode) {
+        if (mSoftKeyboardController != null) {
+            mSoftKeyboardController.dispatchSoftKeyboardShowModeChanged(showMode);
+        }
+    }
+
+    /**
+     * Used to control and query the soft keyboard show mode.
+     */
+    public static final class SoftKeyboardController {
+        private final AccessibilityService mService;
+
+        /**
+         * Map of listeners to their handlers. Lazily created when adding the first
+         * soft keyboard change listener.
+         */
+        private ArrayMap<OnShowModeChangedListener, Handler> mListeners;
+        private final Object mLock;
+
+        SoftKeyboardController(@NonNull AccessibilityService service, @NonNull Object lock) {
+            mService = service;
+            mLock = lock;
+        }
+
+        /**
+         * Called when the service is connected.
+         */
+        void onServiceConnected() {
+            synchronized(mLock) {
+                if (mListeners != null && !mListeners.isEmpty()) {
+                    setSoftKeyboardCallbackEnabled(true);
+                }
+            }
+        }
+
+        /**
+         * Adds the specified change listener to the list of show mode change listeners. The
+         * callback will occur on the service's main thread. Listener is not called on registration.
+         */
+        public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+            addOnShowModeChangedListener(listener, null);
+        }
+
+        /**
+         * Adds the specified change listener to the list of soft keyboard show mode change
+         * listeners. The callback will occur on the specified {@link Handler}'s thread, or on the
+         * services's main thread if the handler is {@code null}.
+         *
+         * @param listener the listener to add, must be non-null
+         * @param handler the handler on which to callback should execute, or {@code null} to
+         *        execute on the service's main thread
+         */
+        public void addOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener,
+                @Nullable Handler handler) {
+            synchronized (mLock) {
+                if (mListeners == null) {
+                    mListeners = new ArrayMap<>();
+                }
+
+                final boolean shouldEnableCallback = mListeners.isEmpty();
+                mListeners.put(listener, handler);
+
+                if (shouldEnableCallback) {
+                    // This may fail if the service is not connected yet, but if we still have
+                    // listeners when it connects, we can try again.
+                    setSoftKeyboardCallbackEnabled(true);
+                }
+            }
+        }
+
+        /**
+         * Removes all instances of the specified change listener from teh list of magnification
+         * change listeners.
+         *
+         * @param listener the listener to remove, must be non-null
+         * @return {@code true} if at least one instance of the listener was removed
+         */
+        public boolean removeOnShowModeChangedListener(@NonNull OnShowModeChangedListener listener) {
+            if (mListeners == null) {
+                return false;
+            }
+
+            synchronized (mLock) {
+                final int keyIndex = mListeners.indexOfKey(listener);
+                final boolean hasKey = keyIndex >= 0;
+                if (hasKey) {
+                    mListeners.removeAt(keyIndex);
+                }
+
+                if (hasKey && mListeners.isEmpty()) {
+                    // We just removed the last listener, so we don't need callbacks from the
+                    // service anymore.
+                    setSoftKeyboardCallbackEnabled(false);
+                }
+
+                return hasKey;
+            }
+        }
+
+        private void setSoftKeyboardCallbackEnabled(boolean enabled) {
+            final IAccessibilityServiceConnection connection =
+                    AccessibilityInteractionClient.getInstance().getConnection(
+                            mService.mConnectionId);
+            if (connection != null) {
+                try {
+                    connection.setSoftKeyboardCallbackEnabled(enabled);
+                } catch (RemoteException re) {
+                    throw new RuntimeException(re);
+                }
+            }
+        }
+
+        /**
+         * Dispatches the soft keyboard show mode change to any registered listeners. This should
+         * be called on the service's main thread.
+         */
+        void dispatchSoftKeyboardShowModeChanged(final int showMode) {
+            final ArrayMap<OnShowModeChangedListener, Handler> entries;
+            synchronized (mLock) {
+                if (mListeners == null || mListeners.isEmpty()) {
+                    Slog.d(LOG_TAG, "Received soft keyboard show mode changed callback"
+                            + " with no listeners registered!");
+                    setSoftKeyboardCallbackEnabled(false);
+                    return;
+                }
+
+                // Listeners may remove themselves. Perform a shallow copy to avoid concurrent
+                // modification.
+                entries = new ArrayMap<>(mListeners);
+            }
+
+            for (int i = 0, count = entries.size(); i < count; i++) {
+                final OnShowModeChangedListener listener = entries.keyAt(i);
+                final Handler handler = entries.valueAt(i);
+                if (handler != null) {
+                    handler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            listener.onShowModeChanged(SoftKeyboardController.this, showMode);
+                        }
+                    });
+                } else {
+                    // We're already on the main thread, just run the listener.
+                    listener.onShowModeChanged(this, showMode);
+                }
+            }
+        }
+
+        /**
+         * Returns the show mode of the soft keyboard. The default show mode is
+         * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+         * input field is focused. An AccessibilityService can also request the show mode
+         * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+         *
+         * @return the current soft keyboard show mode
+         *
+         * @see Settings#Secure#SHOW_MODE_AUTO
+         * @see Settings#Secure#SHOW_MODE_HIDDEN
+         */
+        @SoftKeyboardShowMode
+        public int getShowMode() {
+           try {
+               return Settings.Secure.getInt(mService.getContentResolver(),
+                       Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+           } catch (Settings.SettingNotFoundException e) {
+               Log.v(LOG_TAG, "Failed to obtain the soft keyboard mode", e);
+               // The settings hasn't been changed yet, so it's value is null. Return the default.
+               return 0;
+           }
+        }
+
+        /**
+         * Sets the soft keyboard show mode. The default show mode is
+         * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+         * input field is focused. An AccessibilityService can also request the show mode
+         * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown. The
+         * The lastto this method will be honored, regardless of any previous calls (including those
+         * made by other AccessibilityServices).
+         * <p>
+         * <strong>Note:</strong> If the service is not yet conected (e.g.
+         * {@link AccessibilityService#onServiceConnected()} has not yet been called) or the
+         * service has been disconnected, this method will hav no effect and return {@code false}.
+         *
+         * @param showMode the new show mode for the soft keyboard
+         * @return {@code true} on success
+         *
+         * @see Settings#Secure#SHOW_MODE_AUTO
+         * @see Settings#Secure#SHOW_MODE_HIDDEN
+         */
+        public boolean setShowMode(@SoftKeyboardShowMode int showMode) {
+           final IAccessibilityServiceConnection connection =
+                   AccessibilityInteractionClient.getInstance().getConnection(
+                           mService.mConnectionId);
+           if (connection != null) {
+               try {
+                   return connection.setSoftKeyboardShowMode(showMode);
+               } catch (RemoteException re) {
+                   Log.w(LOG_TAG, "Falied to set soft keyboard behavior", re);
+               }
+           }
+           return false;
+        }
+
+        /**
+         * Listener for changes in the soft keyboard show mode.
+         */
+        public interface OnShowModeChangedListener {
+           /**
+            * Called when the soft keyboard behavior changes. The default show mode is
+            * {@code Settings.Secure.SHOW_MODE_AUTO}, where the soft keyboard is shown when a text
+            * input field is focused. An AccessibilityService can also request the show mode
+            * {@code Settings.Secure.SHOW_MODE_HIDDEN}, where the soft keyboard is never shown.
+            *
+            * @param controller the soft keyboard controller
+            * @param showMode the current soft keyboard show mode
+            */
+            void onShowModeChanged(@NonNull SoftKeyboardController controller,
+                    @SoftKeyboardShowMode int showMode);
+        }
+    }
+
+    /**
      * Performs a global action. Such an action can be performed
      * at any moment regardless of the current application or user
      * location in that application. For example going back, going
@@ -1184,6 +1455,11 @@
             }
 
             @Override
+            public void onSoftKeyboardShowModeChanged(int showMode) {
+                AccessibilityService.this.onSoftKeyboardShowModeChanged(showMode);
+            }
+
+            @Override
             public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
                 AccessibilityService.this.onPerformGestureResult(sequence, completedSuccessfully);
             }
@@ -1205,7 +1481,8 @@
         private static final int DO_CLEAR_ACCESSIBILITY_CACHE = 5;
         private static final int DO_ON_KEY_EVENT = 6;
         private static final int DO_ON_MAGNIFICATION_CHANGED = 7;
-        private static final int DO_GESTURE_COMPLETE = 8;
+        private static final int DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED = 8;
+        private static final int DO_GESTURE_COMPLETE = 9;
 
         private final HandlerCaller mCaller;
 
@@ -1264,6 +1541,12 @@
             mCaller.sendMessage(message);
         }
 
+        public void onSoftKeyboardShowModeChanged(int showMode) {
+          final Message message =
+                  mCaller.obtainMessageI(DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED, showMode);
+          mCaller.sendMessage(message);
+        }
+
         public void onPerformGestureResult(int sequence, boolean successfully) {
             Message message = mCaller.obtainMessageII(DO_GESTURE_COMPLETE, sequence,
                     successfully ? 1 : 0);
@@ -1354,6 +1637,11 @@
                     mCallback.onMagnificationChanged(region, scale, centerX, centerY);
                 } return;
 
+                case DO_ON_SOFT_KEYBOARD_SHOW_MODE_CHANGED: {
+                    final int showMode = (int) message.arg1;
+                    mCallback.onSoftKeyboardShowModeChanged(showMode);
+                } return;
+
                 case DO_GESTURE_COMPLETE: {
                     final boolean successfully = message.arg2 == 1;
                     mCallback.onPerformGestureResult(message.arg1, successfully);
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
index 6280542..ef05d6f 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceClient.aidl
@@ -43,5 +43,7 @@
 
     void onMagnificationChanged(in Region region, float scale, float centerX, float centerY);
 
+    void onSoftKeyboardShowModeChanged(int showMode);
+
     void onPerformGestureResult(int sequence, boolean completedSuccessfully);
 }
diff --git a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
index e58ef2f..d5e8a11 100644
--- a/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
+++ b/core/java/android/accessibilityservice/IAccessibilityServiceConnection.aidl
@@ -84,5 +84,9 @@
 
     void setMagnificationCallbackEnabled(boolean enabled);
 
+    boolean setSoftKeyboardShowMode(int showMode);
+
+    void setSoftKeyboardCallbackEnabled(boolean enabled);
+
     void sendMotionEvents(int sequence, in ParceledListSlice events);
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 11154f2..dc3f64a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4397,7 +4397,7 @@
             String resolvedType = null;
             if (fillInIntent != null) {
                 fillInIntent.migrateExtraStreamToClipData();
-                fillInIntent.prepareToLeaveProcess();
+                fillInIntent.prepareToLeaveProcess(this);
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -4629,7 +4629,7 @@
                     intent.putExtra(Intent.EXTRA_REFERRER, referrer);
                 }
                 intent.migrateExtraStreamToClipData();
-                intent.prepareToLeaveProcess();
+                intent.prepareToLeaveProcess(this);
                 result = ActivityManagerNative.getDefault()
                     .startActivity(mMainThread.getApplicationThread(), getBasePackageName(),
                             intent, intent.resolveTypeIfNeeded(getContentResolver()), mToken,
@@ -4700,7 +4700,7 @@
         if (mParent == null) {
             try {
                 intent.migrateExtraStreamToClipData();
-                intent.prepareToLeaveProcess();
+                intent.prepareToLeaveProcess(this);
                 return ActivityManagerNative.getDefault()
                     .startNextMatchingActivity(mToken, intent, options);
             } catch (RemoteException e) {
@@ -5128,7 +5128,7 @@
             if (false) Log.v(TAG, "Finishing self: token=" + mToken);
             try {
                 if (resultData != null) {
-                    resultData.prepareToLeaveProcess();
+                    resultData.prepareToLeaveProcess(this);
                 }
                 if (ActivityManagerNative.getDefault()
                         .finishActivity(mToken, resultCode, resultData, finishTask)) {
@@ -5355,7 +5355,7 @@
             @PendingIntent.Flags int flags) {
         String packageName = getPackageName();
         try {
-            data.prepareToLeaveProcess();
+            data.prepareToLeaveProcess(this);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                         ActivityManager.INTENT_SENDER_ACTIVITY_RESULT, packageName,
@@ -6335,10 +6335,10 @@
                 resultData = mResultData;
             }
             if (resultData != null) {
-                resultData.prepareToLeaveProcess();
+                resultData.prepareToLeaveProcess(this);
             }
             try {
-                upIntent.prepareToLeaveProcess();
+                upIntent.prepareToLeaveProcess(this);
                 return ActivityManagerNative.getDefault().navigateUpTo(mToken, upIntent,
                         resultCode, resultData);
             } catch (RemoteException e) {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 1e7457c..100e67b 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -56,6 +56,7 @@
 import android.opengl.GLUtils;
 import android.os.AsyncTask;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Bundle;
 import android.os.Debug;
 import android.os.DropBoxManager;
@@ -4959,16 +4960,22 @@
         }
 
         /**
-         * For apps targetting SDK Honeycomb or later, we don't allow
-         * network usage on the main event loop / UI thread.
-         *
-         * Note to those grepping:  this is what ultimately throws
-         * NetworkOnMainThreadException ...
+         * For apps targetting Honeycomb or later, we don't allow network usage
+         * on the main event loop / UI thread. This is what ultimately throws
+         * {@link NetworkOnMainThreadException}.
          */
-        if (data.appInfo.targetSdkVersion > 9) {
+        if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.HONEYCOMB) {
             StrictMode.enableDeathOnNetwork();
         }
 
+        /**
+         * For apps targetting N or later, we don't allow file:// Uri exposure.
+         * This is what ultimately throws {@link FileUriExposedException}.
+         */
+        if (data.appInfo.targetSdkVersion >= Build.VERSION_CODES.N) {
+            StrictMode.enableDeathOnFileUriExposure();
+        }
+
         NetworkSecurityPolicy.getInstance().setCleartextTrafficPermitted(
                 (data.appInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0);
 
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index fab3740..0d6e93d 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -752,7 +752,7 @@
             String resolvedType = null;
             if (fillInIntent != null) {
                 fillInIntent.migrateExtraStreamToClipData();
-                fillInIntent.prepareToLeaveProcess();
+                fillInIntent.prepareToLeaveProcess(this);
                 resolvedType = fillInIntent.resolveTypeIfNeeded(getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -773,7 +773,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, false,
@@ -790,7 +790,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -805,7 +805,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -822,7 +822,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -839,7 +839,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
@@ -856,7 +856,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, receiverPermissions, AppOpsManager.OP_NONE,
@@ -919,7 +919,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermissions, appOp,
@@ -933,7 +933,7 @@
     public void sendBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(mMainThread.getApplicationThread(),
                     intent, resolvedType, null, Activity.RESULT_OK, null, null, null,
                     AppOpsManager.OP_NONE, null, false, false, user.getIdentifier());
@@ -955,7 +955,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                     mMainThread.getApplicationThread(), intent, resolvedType, null,
                     Activity.RESULT_OK, null, null, receiverPermissions, appOp, null, false, false,
@@ -1006,7 +1006,7 @@
         String[] receiverPermissions = receiverPermission == null ? null
                 : new String[] {receiverPermission};
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, receiverPermissions,
@@ -1022,7 +1022,7 @@
         warnIfCallingFromSystemProcess();
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
@@ -1058,7 +1058,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
@@ -1077,7 +1077,7 @@
             intent.setDataAndType(intent.getData(), resolvedType);
         }
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().unbroadcastIntent(
                     mMainThread.getApplicationThread(), intent, getUserId());
         } catch (RemoteException e) {
@@ -1090,7 +1090,7 @@
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, null, false, true,
@@ -1105,7 +1105,7 @@
     public void sendStickyBroadcastAsUser(Intent intent, UserHandle user, Bundle options) {
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, null,
                 Activity.RESULT_OK, null, null, null, AppOpsManager.OP_NONE, options, false, true,
@@ -1140,7 +1140,7 @@
         }
         String resolvedType = intent.resolveTypeIfNeeded(getContentResolver());
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().broadcastIntent(
                 mMainThread.getApplicationThread(), intent, resolvedType, rd,
                 initialCode, initialData, initialExtras, null,
@@ -1159,7 +1159,7 @@
             intent.setDataAndType(intent.getData(), resolvedType);
         }
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(this);
             ActivityManagerNative.getDefault().unbroadcastIntent(
                     mMainThread.getApplicationThread(), intent, user.getIdentifier());
         } catch (RemoteException e) {
@@ -1262,7 +1262,7 @@
     private ComponentName startServiceCommon(Intent service, UserHandle user) {
         try {
             validateServiceIntent(service);
-            service.prepareToLeaveProcess();
+            service.prepareToLeaveProcess(this);
             ComponentName cn = ActivityManagerNative.getDefault().startService(
                 mMainThread.getApplicationThread(), service, service.resolveTypeIfNeeded(
                             getContentResolver()), getOpPackageName(), user.getIdentifier());
@@ -1291,7 +1291,7 @@
     private boolean stopServiceCommon(Intent service, UserHandle user) {
         try {
             validateServiceIntent(service);
-            service.prepareToLeaveProcess();
+            service.prepareToLeaveProcess(this);
             int res = ActivityManagerNative.getDefault().stopService(
                 mMainThread.getApplicationThread(), service,
                 service.resolveTypeIfNeeded(getContentResolver()), user.getIdentifier());
@@ -1339,7 +1339,7 @@
                     < android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
                 flags |= BIND_WAIVE_PRIORITY;
             }
-            service.prepareToLeaveProcess();
+            service.prepareToLeaveProcess(this);
             int res = ActivityManagerNative.getDefault().bindService(
                 mMainThread.getApplicationThread(), getActivityToken(), service,
                 service.resolveTypeIfNeeded(getContentResolver()),
diff --git a/core/java/android/app/IUiAutomationConnection.aidl b/core/java/android/app/IUiAutomationConnection.aidl
index 2caec369..7640e75 100644
--- a/core/java/android/app/IUiAutomationConnection.aidl
+++ b/core/java/android/app/IUiAutomationConnection.aidl
@@ -33,7 +33,7 @@
  * {@hide}
  */
 interface IUiAutomationConnection {
-    void connect(IAccessibilityServiceClient client);
+    void connect(IAccessibilityServiceClient client, int flags);
     void disconnect();
     boolean injectInputEvent(in InputEvent event, boolean sync);
     boolean setRotation(int rotation);
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 7a0e7f6..fa0fbd1 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -35,10 +35,16 @@
      * 'which' is some combination of:
      *   FLAG_SET_SYSTEM
      *   FLAG_SET_LOCK
+     *
+     * A 'null' cropHint rectangle is explicitly permitted as a sentinel for "whatever
+     * the source image's bounding rect is."
+     *
+     * The completion callback's "onWallpaperChanged()" method is invoked when the
+     * new wallpaper content is ready to display.
      */
     ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
-            out Bundle extras, int which);
-    
+            in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+
     /**
      * Set the live wallpaper. This only affects the system wallpaper.
      */
@@ -54,14 +60,14 @@
      */
     ParcelFileDescriptor getWallpaper(IWallpaperManagerCallback cb,
             out Bundle outParams);
-    
+
     /**
      * If the current system wallpaper is a live wallpaper component, return the
      * information about that wallpaper.  Otherwise, if it is a static image,
      * simply return null.
      */
     WallpaperInfo getWallpaperInfo();
-    
+
     /**
      * Clear the system wallpaper.
      */
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 24a3470..9a88f2c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1503,7 +1503,7 @@
         }
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(who);
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1561,7 +1561,7 @@
             String[] resolvedTypes = new String[intents.length];
             for (int i=0; i<intents.length; i++) {
                 intents[i].migrateExtraStreamToClipData();
-                intents[i].prepareToLeaveProcess();
+                intents[i].prepareToLeaveProcess(who);
                 resolvedTypes[i] = intents[i].resolveTypeIfNeeded(who.getContentResolver());
             }
             int result = ActivityManagerNative.getDefault()
@@ -1622,7 +1622,7 @@
         }
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(who);
             int result = ActivityManagerNative.getDefault()
                 .startActivity(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1682,7 +1682,7 @@
         }
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(who);
             int result = ActivityManagerNative.getDefault()
                 .startActivityAsUser(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1721,7 +1721,7 @@
         }
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(who);
             int result = ActivityManagerNative.getDefault()
                 .startActivityAsCaller(whoThread, who.getBasePackageName(), intent,
                         intent.resolveTypeIfNeeded(who.getContentResolver()),
@@ -1759,7 +1759,7 @@
         }
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(who);
             int result = appTask.startActivity(whoThread.asBinder(), who.getBasePackageName(),
                     intent, intent.resolveTypeIfNeeded(who.getContentResolver()), options);
             checkStartActivityResult(result, intent);
@@ -1837,16 +1837,59 @@
      * {@link Instrumentation} APIs. Using both APIs at the same time is not
      * a mistake by itself but a client has to be aware of the APIs limitations.
      * </p>
-     * @return The UI automation instance.
+     * @return The UI automation instance. If none exists, a new one is created with no flags set.
      *
      * @see UiAutomation
      */
     public UiAutomation getUiAutomation() {
         if (mUiAutomationConnection != null) {
             if (mUiAutomation == null) {
+                return getUiAutomation(0);
+            }
+            return mUiAutomation;
+        }
+        return null;
+    }
+
+    /**
+     * Gets the {@link UiAutomation} instance with flags set.
+     * <p>
+     * <strong>Note:</strong> Only one UiAutomation can be obtained. Calling this method
+     * twice with different flags will fail unless the UiAutomation obtained in the first call
+     * is released with {@link UiAutomation#destroy()}.
+     * </p>
+     * <p>
+     * <strong>Note:</strong> The APIs exposed via the returned {@link UiAutomation}
+     * work across application boundaries while the APIs exposed by the instrumentation
+     * do not. For example, {@link Instrumentation#sendPointerSync(MotionEvent)} will
+     * not allow you to inject the event in an app different from the instrumentation
+     * target, while {@link UiAutomation#injectInputEvent(android.view.InputEvent, boolean)}
+     * will work regardless of the current application.
+     * </p>
+     * <p>
+     * A typical test case should be using either the {@link UiAutomation} or
+     * {@link Instrumentation} APIs. Using both APIs at the same time is not
+     * a mistake by itself but a client has to be aware of the APIs limitations.
+     * </p>
+     *
+     * @param flags The flags to be passed to the UiAutomation, for example
+     *        {@link UiAutomation#FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES}.
+     *
+     * @return The UI automation instance.
+     *
+     * @see UiAutomation
+     */
+    public UiAutomation getUiAutomation(int flags) {
+        if (mUiAutomationConnection != null) {
+            if ((mUiAutomation == null) || (mUiAutomation.isDestroyed())) {
                 mUiAutomation = new UiAutomation(getTargetContext().getMainLooper(),
                         mUiAutomationConnection);
-                mUiAutomation.connect();
+                mUiAutomation.connect(flags);
+            } else {
+                if (mUiAutomation.getFlags() != flags) {
+                    throw new RuntimeException(
+                            "Cannot get a UiAutomation with different flags from the existing one");
+                }
             }
             return mUiAutomation;
         }
@@ -1861,8 +1904,8 @@
             try {
                 Process.setThreadPriority(Process.THREAD_PRIORITY_URGENT_DISPLAY);
             } catch (RuntimeException e) {
-                Log.w(TAG, "Exception setting priority of instrumentation thread "                                            
-                        + Process.myTid(), e);                                                                             
+                Log.w(TAG, "Exception setting priority of instrumentation thread "
+                        + Process.myTid(), e);
             }
             if (mAutomaticPerformanceSnapshots) {
                 startPerformanceSnapshot();
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 0f3aad9..7f037f2 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4384,7 +4384,17 @@
                     view.addView(com.android.internal.R.id.media_actions, button);
                 }
             }
-            handleImage(view  /* addPaddingToMainColumn */);
+            handleImage(view);
+            // handle the content margin
+            int endMargin;
+            if (mBuilder.mN.mLargeIcon != null) {
+                endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+                        R.dimen.notification_content_picture_margin_media);
+            } else {
+                endMargin = mBuilder.mContext.getResources().getDimensionPixelSize(
+                        R.dimen.notification_content_margin_end);
+            }
+            view.setViewLayoutMarginEnd(R.id.notification_main_column, endMargin);
             return view;
         }
 
diff --git a/core/java/android/app/PendingIntent.java b/core/java/android/app/PendingIntent.java
index edafe59..412b098 100644
--- a/core/java/android/app/PendingIntent.java
+++ b/core/java/android/app/PendingIntent.java
@@ -307,7 +307,7 @@
                 context.getContentResolver()) : null;
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -332,7 +332,7 @@
                 context.getContentResolver()) : null;
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_ACTIVITY, packageName,
@@ -446,7 +446,7 @@
         String[] resolvedTypes = new String[intents.length];
         for (int i=0; i<intents.length; i++) {
             intents[i].migrateExtraStreamToClipData();
-            intents[i].prepareToLeaveProcess();
+            intents[i].prepareToLeaveProcess(context);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
         try {
@@ -472,7 +472,7 @@
         String[] resolvedTypes = new String[intents.length];
         for (int i=0; i<intents.length; i++) {
             intents[i].migrateExtraStreamToClipData();
-            intents[i].prepareToLeaveProcess();
+            intents[i].prepareToLeaveProcess(context);
             resolvedTypes[i] = intents[i].resolveTypeIfNeeded(context.getContentResolver());
         }
         try {
@@ -527,7 +527,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_BROADCAST, packageName,
@@ -570,7 +570,7 @@
         String resolvedType = intent != null ? intent.resolveTypeIfNeeded(
                 context.getContentResolver()) : null;
         try {
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(context);
             IIntentSender target =
                 ActivityManagerNative.getDefault().getIntentSender(
                     ActivityManager.INTENT_SENDER_SERVICE, packageName,
diff --git a/core/java/android/app/UiAutomation.java b/core/java/android/app/UiAutomation.java
index dce2e51..5ec59b4 100644
--- a/core/java/android/app/UiAutomation.java
+++ b/core/java/android/app/UiAutomation.java
@@ -105,6 +105,14 @@
     /** Rotation constant: Freeze rotation to 270 degrees . */
     public static final int ROTATION_FREEZE_270 = Surface.ROTATION_270;
 
+    /**
+     * UiAutomation supresses accessibility services by default. This flag specifies that
+     * existing accessibility services should continue to run, and that new ones may start.
+     * This flag is set when obtaining the UiAutomation from
+     * {@link Instrumentation#getUiAutomation(int)}.
+     */
+    public static final int FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES = 0x00000001;
+
     private final Object mLock = new Object();
 
     private final ArrayList<AccessibilityEvent> mEventQueue = new ArrayList<AccessibilityEvent>();
@@ -123,6 +131,10 @@
 
     private boolean mIsConnecting;
 
+    private boolean mIsDestroyed;
+
+    private int mFlags;
+
     /**
      * Listener for observing the {@link AccessibilityEvent} stream.
      */
@@ -182,11 +194,22 @@
     }
 
     /**
-     * Connects this UiAutomation to the accessibility introspection APIs.
+     * Connects this UiAutomation to the accessibility introspection APIs with default flags.
      *
      * @hide
      */
     public void connect() {
+        connect(0);
+    }
+
+    /**
+     * Connects this UiAutomation to the accessibility introspection APIs.
+     *
+     * @param flags Any flags to apply to the automation as it gets connected
+     *
+     * @hide
+     */
+    public void connect(int flags) {
         synchronized (mLock) {
             throwIfConnectedLocked();
             if (mIsConnecting) {
@@ -197,7 +220,8 @@
 
         try {
             // Calling out without a lock held.
-            mUiAutomationConnection.connect(mClient);
+            mUiAutomationConnection.connect(mClient, flags);
+            mFlags = flags;
         } catch (RemoteException re) {
             throw new RuntimeException("Error while connecting UiAutomation", re);
         }
@@ -227,6 +251,17 @@
     }
 
     /**
+     * Get the flags used to connect the service.
+     *
+     * @return The flags used to connect
+     *
+     * @hide
+     */
+    public int getFlags() {
+        return mFlags;
+    }
+
+    /**
      * Disconnects this UiAutomation from the accessibility introspection APIs.
      *
      * @hide
@@ -263,6 +298,17 @@
     }
 
     /**
+     * Reports if the object has been destroyed
+     *
+     * @return {code true} if the object has been destroyed.
+     *
+     * @hide
+     */
+    public boolean isDestroyed() {
+        return mIsDestroyed;
+    }
+
+    /**
      * Sets a callback for observing the stream of {@link AccessibilityEvent}s.
      *
      * @param listener The callback.
@@ -274,6 +320,15 @@
     }
 
     /**
+     * Destroy this UiAutomation. After calling this method, attempting to use the object will
+     * result in errors.
+     */
+    public void destroy() {
+        disconnect();
+        mIsDestroyed = true;
+    }
+
+    /**
      * Performs a global action. Such an action can be performed at any moment
      * regardless of the current application or user location in that application.
      * For example going back, going home, opening recents, etc.
@@ -1033,6 +1088,11 @@
                 }
 
                 @Override
+                public void onSoftKeyboardShowModeChanged(int showMode) {
+                    /* do nothing */
+                }
+
+                @Override
                 public void onPerformGestureResult(int sequence, boolean completedSuccessfully) {
                     /* do nothing */
                 }
diff --git a/core/java/android/app/UiAutomationConnection.java b/core/java/android/app/UiAutomationConnection.java
index bd10267..276f774 100644
--- a/core/java/android/app/UiAutomationConnection.java
+++ b/core/java/android/app/UiAutomationConnection.java
@@ -77,7 +77,7 @@
 
     private int mOwningUid;
 
-    public void connect(IAccessibilityServiceClient client) {
+    public void connect(IAccessibilityServiceClient client, int flags) {
         if (client == null) {
             throw new IllegalArgumentException("Client cannot be null!");
         }
@@ -87,7 +87,7 @@
                 throw new IllegalStateException("Already connected.");
             }
             mOwningUid = Binder.getCallingUid();
-            registerUiTestAutomationServiceLocked(client);
+            registerUiTestAutomationServiceLocked(client, flags);
             storeRotationStateLocked();
         }
     }
@@ -322,7 +322,8 @@
         }
     }
 
-    private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client) {
+    private void registerUiTestAutomationServiceLocked(IAccessibilityServiceClient client,
+            int flags) {
         IAccessibilityManager manager = IAccessibilityManager.Stub.asInterface(
                 ServiceManager.getService(Context.ACCESSIBILITY_SERVICE));
         AccessibilityServiceInfo info = new AccessibilityServiceInfo();
@@ -337,7 +338,7 @@
         try {
             // Calling out with a lock held is fine since if the system
             // process is gone the client calling in will be killed.
-            manager.registerUiTestAutomationService(mToken, client, info);
+            manager.registerUiTestAutomationService(mToken, client, info, flags);
             mClient = client;
         } catch (RemoteException re) {
             throw new IllegalStateException("Error while registering UiTestAutomationService.", re);
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index f103576..b0ffd21 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -64,6 +64,8 @@
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
 import java.util.List;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Provides access to the system wallpaper. With WallpaperManager, you can
@@ -770,18 +772,26 @@
             return 0;
         }
         final Bundle result = new Bundle();
+        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             Resources resources = mContext.getResources();
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
                     "res:" + resources.getResourceName(resid),
-                    mContext.getOpPackageName(), result, which);
+                    mContext.getOpPackageName(), null, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
+                boolean ok = false;
                 try {
                     fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
                     copyStreamToWallpaperFile(resources.openRawResource(resid), fos);
+                    // The 'close()' is the trigger for any server-side image manipulation,
+                    // so we must do that before waiting for completion.
+                    fos.close();
+                    completion.waitForCompletion();
                 } finally {
+                    // Might be redundant but completion shouldn't wait unless the write
+                    // succeeded; this is a fallback if it threw past the close+wait.
                     IoUtils.closeQuietly(fos);
                 }
             }
@@ -876,14 +886,17 @@
             return 0;
         }
         final Bundle result = new Bundle();
+        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), result, which);
+                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
                     fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
                     fullImage.compress(Bitmap.CompressFormat.PNG, 90, fos);
+                    fos.close();
+                    completion.waitForCompletion();
                 } finally {
                     IoUtils.closeQuietly(fos);
                 }
@@ -990,14 +1003,17 @@
             return 0;
         }
         final Bundle result = new Bundle();
+        final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), result, which);
+                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
                     fos = new ParcelFileDescriptor.AutoCloseOutputStream(fd);
                     copyStreamToWallpaperFile(bitmapData, fos);
+                    fos.close();
+                    completion.waitForCompletion();
                 } finally {
                     IoUtils.closeQuietly(fos);
                 }
@@ -1385,4 +1401,28 @@
 
         return null;
     }
+
+    // Private completion callback for setWallpaper() synchronization
+    private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
+        final CountDownLatch mLatch;
+
+        public WallpaperSetCompletion() {
+            mLatch = new CountDownLatch(1);
+        }
+
+        public void waitForCompletion() {
+            try {
+                mLatch.await(30, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+                // This might be legit: the crop may take a very long time. Don't sweat
+                // it in that case; we are okay with display lagging behind in order to
+                // keep the caller from locking up indeterminately.
+            }
+        }
+
+        @Override
+        public void onWallpaperChanged() throws RemoteException {
+            mLatch.countDown();
+        }
+    }
 }
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index e4e97a1..c79c407 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -3346,6 +3346,10 @@
      * <p>If the device owner information contains only whitespaces then the message on the lock
      * screen will be blank and the user will not be allowed to change it.
      *
+     * <p>If the device owner information needs to be localized, it is the responsibility of the
+     * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+     * and set a new version of this string accordingly.
+     *
      * @param admin The name of the admin component to check.
      * @param info Device owner information which will be displayed instead of the user
      * owner info.
@@ -5211,6 +5215,10 @@
      *  for support."
      * If the message is longer than 200 characters it may be truncated.
      *
+     * <p>If the short support message needs to be localized, it is the responsibility of the
+     * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+     * and set a new version of this string accordingly.
+     *
      * @see #setLongSupportMessage
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5250,6 +5258,10 @@
      * Called by a device admin to set the long support message. This will
      * be displayed to the user in the device administators settings screen.
      *
+     * <p>If the long support message needs to be localized, it is the responsibility of the
+     * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+     * and set a new version of this string accordingly.
+     *
      * @see #setShortSupportMessage
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
@@ -5414,6 +5426,58 @@
     }
 
     /**
+     * Called by a profile owner of a managed profile to set the name of the organization under
+     * management.
+     *
+     * <p>If the organization name needs to be localized, it is the responsibility of the
+     * {@link DeviceAdminReceiver} to listen to the {@link Intent#ACTION_LOCALE_CHANGED} broadcast
+     * and set a new version of this string accordingly.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param title The organization name or {@code null} to clear a previously set name.
+     */
+    public void setOrganizationName(@NonNull ComponentName admin, @Nullable String title) {
+        try {
+            mService.setOrganizationName(admin, title);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+        }
+    }
+
+    /**
+     * Called by a profile owner of a managed profile to retrieve the name of the organization
+     * under management.
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @return The organization name or {@code null} if none is set.
+     */
+    public String getOrganizationName(@NonNull ComponentName admin) {
+        try {
+            return mService.getOrganizationName(admin);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            return null;
+        }
+    }
+
+    /**
+     * Retrieve the default title message used in the confirm credentials screen for a given user.
+     *
+     * @param userHandle The user id of the user we're interested in.
+     * @return The organization name or {@code null} if none is set.
+     *
+     * @hide
+     */
+    public String getOrganizationNameForUser(int userHandle) {
+        try {
+            return mService.getOrganizationNameForUser(userHandle);
+        } catch (RemoteException re) {
+            Log.w(TAG, REMOTE_EXCEPTION_MESSAGE);
+            return null;
+        }
+    }
+
+    /**
      * @return the {@link UserProvisioningState} for the current user - for unmanaged users will
      *         return {@link #STATE_USER_UNMANAGED}
      * @hide
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 6333013..37d13e5 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -276,6 +276,10 @@
     int getOrganizationColor(in ComponentName admin);
     int getOrganizationColorForUser(int userHandle);
 
+    void setOrganizationName(in ComponentName admin, in String title);
+    String getOrganizationName(in ComponentName admin);
+    String getOrganizationNameForUser(int userHandle);
+
     int getUserProvisioningState();
     void setUserProvisioningState(int state, int userHandle);
 
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index 2260d7e..10e6fb2 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -522,7 +522,7 @@
         IActivityManager am = ActivityManagerNative.getDefault();
         IBinder binder = null;
         try {
-            service.prepareToLeaveProcess();
+            service.prepareToLeaveProcess(myContext);
             binder = am.peekService(service, service.resolveTypeIfNeeded(
                     myContext.getContentResolver()), myContext.getOpPackageName());
         } catch (RemoteException e) {
diff --git a/core/java/android/content/ClipData.java b/core/java/android/content/ClipData.java
index 6dfefac..0ec58ea 100644
--- a/core/java/android/content/ClipData.java
+++ b/core/java/android/content/ClipData.java
@@ -823,14 +823,14 @@
      *
      * @hide
      */
-    public void prepareToLeaveProcess() {
+    public void prepareToLeaveProcess(boolean leavingPackage) {
         final int size = mItems.size();
         for (int i = 0; i < size; i++) {
             final Item item = mItems.get(i);
             if (item.mIntent != null) {
-                item.mIntent.prepareToLeaveProcess();
+                item.mIntent.prepareToLeaveProcess(leavingPackage);
             }
-            if (item.mUri != null && StrictMode.vmFileUriExposureEnabled()) {
+            if (item.mUri != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
                 item.mUri.checkFileUriExposed("ClipData.Item.getUri()");
             }
         }
diff --git a/core/java/android/content/ClipboardManager.java b/core/java/android/content/ClipboardManager.java
index 5653cad..e67da2b 100644
--- a/core/java/android/content/ClipboardManager.java
+++ b/core/java/android/content/ClipboardManager.java
@@ -118,7 +118,7 @@
     public void setPrimaryClip(ClipData clip) {
         try {
             if (clip != null) {
-                clip.prepareToLeaveProcess();
+                clip.prepareToLeaveProcess(true);
             }
             getService().setPrimaryClip(clip, mContext.getOpPackageName());
         } catch (RemoteException e) {
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 49b8363..ee469da 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -8912,23 +8912,46 @@
      *
      * @hide
      */
-    public void prepareToLeaveProcess() {
+    public void prepareToLeaveProcess(Context context) {
+        final boolean leavingPackage = (mComponent == null)
+                || !Objects.equals(mComponent.getPackageName(), context.getPackageName());
+        prepareToLeaveProcess(leavingPackage);
+    }
+
+    /**
+     * Prepare this {@link Intent} to leave an app process.
+     *
+     * @hide
+     */
+    public void prepareToLeaveProcess(boolean leavingPackage) {
         setAllowFds(false);
 
         if (mSelector != null) {
-            mSelector.prepareToLeaveProcess();
+            mSelector.prepareToLeaveProcess(leavingPackage);
         }
         if (mClipData != null) {
-            mClipData.prepareToLeaveProcess();
+            mClipData.prepareToLeaveProcess(leavingPackage);
         }
 
-        if (mData != null && StrictMode.vmFileUriExposureEnabled()) {
-            // There are several ACTION_MEDIA_* broadcasts that send file://
-            // Uris, so only check common actions.
-            if (ACTION_VIEW.equals(mAction) ||
-                    ACTION_EDIT.equals(mAction) ||
-                    ACTION_ATTACH_DATA.equals(mAction)) {
-                mData.checkFileUriExposed("Intent.getData()");
+        if (mData != null && StrictMode.vmFileUriExposureEnabled() && leavingPackage) {
+            switch (mAction) {
+                case ACTION_MEDIA_REMOVED:
+                case ACTION_MEDIA_UNMOUNTED:
+                case ACTION_MEDIA_CHECKING:
+                case ACTION_MEDIA_NOFS:
+                case ACTION_MEDIA_MOUNTED:
+                case ACTION_MEDIA_SHARED:
+                case ACTION_MEDIA_UNSHARED:
+                case ACTION_MEDIA_BAD_REMOVAL:
+                case ACTION_MEDIA_UNMOUNTABLE:
+                case ACTION_MEDIA_EJECT:
+                case ACTION_MEDIA_SCANNER_STARTED:
+                case ACTION_MEDIA_SCANNER_FINISHED:
+                case ACTION_MEDIA_SCANNER_SCAN_FILE:
+                    // Ignore legacy actions
+                    break;
+                default:
+                    mData.checkFileUriExposed("Intent.getData()");
             }
         }
     }
diff --git a/core/java/android/hardware/input/KeyboardLayout.java b/core/java/android/hardware/input/KeyboardLayout.java
index 584008c..2cafa08 100644
--- a/core/java/android/hardware/input/KeyboardLayout.java
+++ b/core/java/android/hardware/input/KeyboardLayout.java
@@ -16,8 +16,10 @@
 
 package android.hardware.input;
 
+import android.annotation.NonNull;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.util.LocaleList;
 
 import java.util.Locale;
 
@@ -32,7 +34,8 @@
     private final String mLabel;
     private final String mCollection;
     private final int mPriority;
-    private final Locale[] mLocales;
+    @NonNull
+    private final LocaleList mLocales;
     private final int mVendorId;
     private final int mProductId;
 
@@ -47,16 +50,12 @@
     };
 
     public KeyboardLayout(String descriptor, String label, String collection, int priority,
-            Locale[] locales, int vid, int pid) {
+            LocaleList locales, int vid, int pid) {
         mDescriptor = descriptor;
         mLabel = label;
         mCollection = collection;
         mPriority = priority;
-        if (locales != null) {
-            mLocales = locales;
-        } else {
-            mLocales = new Locale[0];
-        }
+        mLocales = locales;
         mVendorId = vid;
         mProductId = pid;
     }
@@ -66,11 +65,7 @@
         mLabel = source.readString();
         mCollection = source.readString();
         mPriority = source.readInt();
-        int N = source.readInt();
-        mLocales = new Locale[N];
-        for (int i = 0; i < N; i++) {
-            mLocales[i] = Locale.forLanguageTag(source.readString());
-        }
+        mLocales = LocaleList.CREATOR.createFromParcel(source);
         mVendorId = source.readInt();
         mProductId = source.readInt();
     }
@@ -108,7 +103,7 @@
      * This may be empty if a locale has not been assigned to this keyboard layout.
      * @return The keyboard layout's intended locale.
      */
-    public Locale[] getLocales() {
+    public LocaleList getLocales() {
         return mLocales;
     }
 
@@ -141,14 +136,7 @@
         dest.writeString(mLabel);
         dest.writeString(mCollection);
         dest.writeInt(mPriority);
-        if (mLocales != null) {
-            dest.writeInt(mLocales.length);
-            for (Locale l : mLocales) {
-                dest.writeString(l.toLanguageTag());
-            }
-        } else {
-            dest.writeInt(0);
-        }
+        mLocales.writeToParcel(dest, 0);
         dest.writeInt(mVendorId);
         dest.writeInt(mProductId);
     }
diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 4a8dfbc..53b027b 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -2343,7 +2343,7 @@
      */
     public void checkFileUriExposed(String location) {
         if ("file".equals(getScheme())) {
-            StrictMode.onFileUriExposed(location);
+            StrictMode.onFileUriExposed(this, location);
         }
     }
 
diff --git a/core/java/android/os/FileUriExposedException.java b/core/java/android/os/FileUriExposedException.java
new file mode 100644
index 0000000..e47abe2
--- /dev/null
+++ b/core/java/android/os/FileUriExposedException.java
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2016 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.os;
+
+import android.content.Intent;
+
+/**
+ * The exception that is thrown when an application exposes a {@code file://}
+ * {@link android.net.Uri} to another app.
+ * <p>
+ * This exposure is discouraged since the receiving app may not have access to
+ * the shared path. For example, the receiving app may not have requested the
+ * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime permission,
+ * or the platform may be sharing the {@link android.net.Uri} across user
+ * profile boundaries.
+ * <p>
+ * Instead, apps should use {@code content://} Uris so the platform can extend
+ * temporary permission for the receiving app to access the resource.
+ * <p>
+ * This is only thrown for applications targeting {@link Build.VERSION_CODES#N}
+ * or higher. Applications targeting earlier SDK versions are allowed to share
+ * {@code file://} {@link android.net.Uri}, but it's strongly discouraged.
+ *
+ * @see android.support.v4.content.FileProvider
+ * @see Intent#FLAG_GRANT_READ_URI_PERMISSION
+ */
+public class FileUriExposedException extends RuntimeException {
+    public FileUriExposedException(String message) {
+        super(message);
+    }
+}
diff --git a/core/java/android/os/StrictMode.java b/core/java/android/os/StrictMode.java
index f1672df..91d88da 100644
--- a/core/java/android/os/StrictMode.java
+++ b/core/java/android/os/StrictMode.java
@@ -24,6 +24,7 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.ServiceConnection;
+import android.net.Uri;
 import android.util.ArrayMap;
 import android.util.Log;
 import android.util.Printer;
@@ -46,7 +47,6 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
-import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 /**
@@ -243,42 +243,15 @@
 
     // Byte 3: Penalty
 
-    /**
-     * @hide
-     */
+    /** {@hide} */
     public static final int PENALTY_LOG = 0x01 << 16;  // normal android.util.Log
-
-    // Used for both process and thread policy:
-
-    /**
-     * @hide
-     */
+    /** {@hide} */
     public static final int PENALTY_DIALOG = 0x02 << 16;
-
-    /**
-     * Death on any detected violation.
-     *
-     * @hide
-     */
+    /** {@hide} */
     public static final int PENALTY_DEATH = 0x04 << 16;
-
-    /**
-     * Death just for detected network usage.
-     *
-     * @hide
-     */
-    public static final int PENALTY_DEATH_ON_NETWORK = 0x08 << 16;
-
-    /**
-     * Flash the screen during violations.
-     *
-     * @hide
-     */
+    /** {@hide} */
     public static final int PENALTY_FLASH = 0x10 << 16;
-
-    /**
-     * @hide
-     */
+    /** {@hide} */
     public static final int PENALTY_DROPBOX = 0x20 << 16;
 
     /**
@@ -294,12 +267,28 @@
      */
     public static final int PENALTY_GATHER = 0x40 << 16;
 
+    // Byte 4: Special cases
+
+    /**
+     * Death when network traffic is detected on main thread.
+     *
+     * @hide
+     */
+    public static final int PENALTY_DEATH_ON_NETWORK = 0x01 << 24;
+
     /**
      * Death when cleartext network traffic is detected.
      *
      * @hide
      */
-    public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x80 << 16;
+    public static final int PENALTY_DEATH_ON_CLEARTEXT_NETWORK = 0x02 << 24;
+
+    /**
+     * Death when file exposure is detected.
+     *
+     * @hide
+     */
+    public static final int PENALTY_DEATH_ON_FILE_URI_EXPOSURE = 0x04 << 24;
 
     /**
      * Mask of all the penalty bits valid for thread policies.
@@ -312,7 +301,7 @@
      * Mask of all the penalty bits valid for VM policies.
      */
     private static final int VM_PENALTY_MASK = PENALTY_LOG | PENALTY_DEATH | PENALTY_DROPBOX
-            | PENALTY_DEATH_ON_CLEARTEXT_NETWORK;
+            | PENALTY_DEATH_ON_CLEARTEXT_NETWORK | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
 
     /** {@hide} */
     public static final int NETWORK_POLICY_ACCEPT = 0;
@@ -748,10 +737,22 @@
             }
 
             /**
-             * Detect when a {@code file://} {@link android.net.Uri} is exposed beyond this
-             * app. The receiving app may not have access to the sent path.
-             * Instead, when sharing files between apps, {@code content://}
-             * should be used with permission grants.
+             * Detect when this application exposes a {@code file://}
+             * {@link android.net.Uri} to another app.
+             * <p>
+             * This exposure is discouraged since the receiving app may not have
+             * access to the shared path. For example, the receiving app may not
+             * have requested the
+             * {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} runtime
+             * permission, or the platform may be sharing the
+             * {@link android.net.Uri} across user profile boundaries.
+             * <p>
+             * Instead, apps should use {@code content://} Uris so the platform
+             * can extend temporary permission for the receiving app to access
+             * the resource.
+             *
+             * @see android.support.v4.content.FileProvider
+             * @see Intent#FLAG_GRANT_READ_URI_PERMISSION
              */
             public Builder detectFileUriExposure() {
                 return enable(DETECT_VM_FILE_URI_EXPOSURE);
@@ -798,6 +799,16 @@
             }
 
             /**
+             * Crashes the whole process when a {@code file://}
+             * {@link android.net.Uri} is exposed beyond this app.
+             *
+             * @see #detectFileUriExposure()
+             */
+            public Builder penaltyDeathOnFileUriExposure() {
+                return enable(PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
+            }
+
+            /**
              * Log detected violations to the system log.
              */
             public Builder penaltyLog() {
@@ -1111,6 +1122,25 @@
     }
 
     /**
+     * Used by the framework to make file usage a fatal error.
+     *
+     * @hide
+     */
+    public static void enableDeathOnFileUriExposure() {
+        sVmPolicyMask |= DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE;
+    }
+
+    /**
+     * Used by lame internal apps that haven't done the hard work to get
+     * themselves off file:// Uris yet.
+     *
+     * @hide
+     */
+    public static void disableDeathOnFileUriExposure() {
+        sVmPolicyMask &= ~(DETECT_VM_FILE_URI_EXPOSURE | PENALTY_DEATH_ON_FILE_URI_EXPOSURE);
+    }
+
+    /**
      * Parses the BlockGuard policy mask out from the Exception's
      * getMessage() String value.  Kinda gross, but least
      * invasive.  :/
@@ -1755,9 +1785,13 @@
     /**
      * @hide
      */
-    public static void onFileUriExposed(String location) {
-        final String message = "file:// Uri exposed through " + location;
-        onVmPolicyViolation(null, new Throwable(message));
+    public static void onFileUriExposed(Uri uri, String location) {
+        final String message = uri + " exposed beyond app through " + location;
+        if ((sVmPolicyMask & PENALTY_DEATH_ON_FILE_URI_EXPOSURE) != 0) {
+            throw new FileUriExposedException(message);
+        } else {
+            onVmPolicyViolation(null, new Throwable(message));
+        }
     }
 
     /**
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index c9c0cde..6e92ec1 100755
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -4856,6 +4856,29 @@
                 "accessibility_display_magnification_auto_update";
 
         /**
+         * Setting that specifies what mode the soft keyboard is in (default or hidden). Can be
+         * modified from an AccessibilityService using the SoftKeyboardController.
+         *
+         * @hide
+         */
+        public static final String ACCESSIBILITY_SOFT_KEYBOARD_MODE =
+                "accessibility_soft_keyboard_mode";
+
+        /**
+         * Default soft keyboard behavior.
+         *
+         * @hide
+         */
+        public static final int SHOW_MODE_AUTO = 0;
+
+        /**
+         * Soft keyboard is never shown.
+         *
+         * @hide
+         */
+        public static final int SHOW_MODE_HIDDEN = 1;
+
+        /**
          * Setting that specifies whether timed text (captions) should be
          * displayed in video content. Text display properties are controlled by
          * the following settings:
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 0c6a0c6..6ff9fe7 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -1170,7 +1170,7 @@
         }
         try {
             intent.migrateExtraStreamToClipData();
-            intent.prepareToLeaveProcess();
+            intent.prepareToLeaveProcess(mContext);
             int res = mSystemService.startVoiceActivity(mToken, intent,
                     intent.resolveType(mContext.getContentResolver()));
             Instrumentation.checkStartActivityResult(res, intent);
diff --git a/core/java/android/view/KeyboardShortcutGroup.java b/core/java/android/view/KeyboardShortcutGroup.java
index 013255b..57d07c0 100644
--- a/core/java/android/view/KeyboardShortcutGroup.java
+++ b/core/java/android/view/KeyboardShortcutGroup.java
@@ -32,6 +32,8 @@
 public final class KeyboardShortcutGroup implements Parcelable {
     private final CharSequence mLabel;
     private final List<KeyboardShortcutInfo> mItems;
+    // The system group looks different UI wise.
+    private boolean mSystemGroup;
 
     /**
      * @param label The title to be used for this group, or null if there is none.
@@ -50,10 +52,33 @@
         this(label, Collections.<KeyboardShortcutInfo>emptyList());
     }
 
+    /**
+     * @param label The title to be used for this group, or null if there is none.
+     * @param items The set of items to be included.
+     * @param isSystemGroup Set this to {@code true} if this is s system group.
+     * @hide
+     */
+    public KeyboardShortcutGroup(@Nullable CharSequence label,
+            @NonNull List<KeyboardShortcutInfo> items, boolean isSystemGroup) {
+        mLabel = label;
+        mItems = new ArrayList<>(checkNotNull(items));
+        mSystemGroup = isSystemGroup;
+    }
+
+    /**
+     * @param label The title to be used for this group, or null if there is none.
+     * @param isSystemGroup Set this to {@code true} if this is s system group.
+     * @hide
+     */
+    public KeyboardShortcutGroup(@Nullable CharSequence label, boolean isSystemGroup) {
+        this(label, Collections.<KeyboardShortcutInfo>emptyList(), isSystemGroup);
+    }
+
     private KeyboardShortcutGroup(Parcel source) {
         mItems = new ArrayList<>();
         mLabel = source.readCharSequence();
         source.readTypedList(mItems, KeyboardShortcutInfo.CREATOR);
+        mSystemGroup = source.readInt() == 1;
     }
 
     /**
@@ -70,6 +95,11 @@
         return mItems;
     }
 
+    /** @hide **/
+    public boolean isSystemGroup() {
+        return mSystemGroup;
+    }
+
     /**
      * Adds an item to the existing list.
      *
@@ -88,6 +118,7 @@
     public void writeToParcel(Parcel dest, int flags) {
         dest.writeCharSequence(mLabel);
         dest.writeTypedList(mItems);
+        dest.writeInt(mSystemGroup ? 1 : 0);
     }
 
     public static final Creator<KeyboardShortcutGroup> CREATOR =
@@ -99,4 +130,4 @@
             return new KeyboardShortcutGroup[size];
         }
     };
-}
\ No newline at end of file
+}
diff --git a/core/java/android/view/NotificationHeaderView.java b/core/java/android/view/NotificationHeaderView.java
index 1c0ea0f..34713ad 100644
--- a/core/java/android/view/NotificationHeaderView.java
+++ b/core/java/android/view/NotificationHeaderView.java
@@ -25,8 +25,6 @@
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
-import com.android.internal.R;
-
 import java.util.ArrayList;
 
 /**
@@ -39,6 +37,7 @@
     public static final int NO_COLOR = -1;
     private final int mHeaderMinWidth;
     private final int mExpandTopPadding;
+    private final int mContentEndMargin;
     private View mAppName;
     private View mSubTextView;
     private OnClickListener mExpandClickListener;
@@ -51,6 +50,7 @@
     private int mOriginalNotificationColor;
     private boolean mGroupHeader;
     private boolean mExpanded;
+    private boolean mShowWorkBadgeAtEnd;
 
     public NotificationHeaderView(Context context) {
         this(context, null);
@@ -68,6 +68,8 @@
         super(context, attrs, defStyleAttr, defStyleRes);
         mHeaderMinWidth = getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_header_shrink_min_width);
+        mContentEndMargin = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin_end);
         mExpandTopPadding = (int) (1 * getResources().getDisplayMetrics().density);
     }
 
@@ -135,6 +137,9 @@
         super.onLayout(changed, l, t, r, b);
         if (mProfileBadge.getVisibility() != View.GONE) {
             int paddingEnd = getPaddingEnd();
+            if (mShowWorkBadgeAtEnd) {
+                paddingEnd = mContentEndMargin;
+            }
             if (getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
                 mProfileBadge.layout(paddingEnd,
                         mProfileBadge.getTop(),
@@ -225,6 +230,17 @@
         mExpandButton.setPadding(0, paddingTop, 0, 0);
     }
 
+    public void setShowWorkBadgeAtEnd(boolean showWorkBadgeAtEnd) {
+        if (showWorkBadgeAtEnd != mShowWorkBadgeAtEnd) {
+            setClipToPadding(!showWorkBadgeAtEnd);
+            mShowWorkBadgeAtEnd = showWorkBadgeAtEnd;
+        }
+    }
+
+    public View getWorkProfileIcon() {
+        return mProfileBadge;
+    }
+
     public class HeaderTouchListener implements View.OnTouchListener {
 
         private final ArrayList<Rect> mTouchRects = new ArrayList<>();
diff --git a/core/java/android/view/PointerIcon.java b/core/java/android/view/PointerIcon.java
index 7ba046b..81bb638 100644
--- a/core/java/android/view/PointerIcon.java
+++ b/core/java/android/view/PointerIcon.java
@@ -139,9 +139,7 @@
 
     private static final PointerIcon gNullIcon = new PointerIcon(STYLE_NULL);
     private static final SparseArray<PointerIcon> gSystemIcons = new SparseArray<PointerIcon>();
-
-    /** @hide */
-    public static boolean sUseLargeIcons = false;
+    private static boolean sUseLargeIcons = false;
 
     private final int mStyle;
     private int mSystemIconResourceId;
@@ -235,6 +233,15 @@
     }
 
     /**
+     * Updates wheter accessibility large icons are used or not.
+     * @hide
+     */
+    public static void setUseLargeIcons(boolean use) {
+        sUseLargeIcons = use;
+        gSystemIcons.clear();
+    }
+
+    /**
      * Creates a custom pointer from the given bitmap and hotspot information.
      *
      * @param bitmap The bitmap for the icon.
diff --git a/core/java/android/view/accessibility/IAccessibilityManager.aidl b/core/java/android/view/accessibility/IAccessibilityManager.aidl
index 9e79057..655c9b3 100644
--- a/core/java/android/view/accessibility/IAccessibilityManager.aidl
+++ b/core/java/android/view/accessibility/IAccessibilityManager.aidl
@@ -51,7 +51,7 @@
     void removeAccessibilityInteractionConnection(IWindow windowToken);
 
     void registerUiTestAutomationService(IBinder owner, IAccessibilityServiceClient client,
-        in AccessibilityServiceInfo info);
+        in AccessibilityServiceInfo info, int flags);
 
     void unregisterUiTestAutomationService(IAccessibilityServiceClient client);
 
diff --git a/core/java/android/widget/AbsListView.java b/core/java/android/widget/AbsListView.java
index df84970..7b6fa6d 100644
--- a/core/java/android/widget/AbsListView.java
+++ b/core/java/android/widget/AbsListView.java
@@ -565,6 +565,12 @@
     private Runnable mTouchModeReset;
 
     /**
+     * Whether the most recent touch event stream resulted in a successful
+     * long-press action. This is reset on TOUCH_DOWN.
+     */
+    private boolean mHasPerformedLongPress;
+
+    /**
      * This view is in transcript mode -- it shows the bottom of the list when the data
      * changes
      */
@@ -3108,7 +3114,9 @@
                         handled = performLongPress(child, longPressPosition, longPressId);
                     }
                 }
+
                 if (handled) {
+                    mHasPerformedLongPress = true;
                     mTouchMode = TOUCH_MODE_REST;
                     setPressed(false);
                     child.setPressed(false);
@@ -3811,6 +3819,7 @@
     }
 
     private void onTouchDown(MotionEvent ev) {
+        mHasPerformedLongPress = false;
         mActivePointerId = ev.getPointerId(0);
 
         if (mTouchMode == TOUCH_MODE_OVERFLING) {
@@ -3874,6 +3883,11 @@
     }
 
     private void onTouchMove(MotionEvent ev, MotionEvent vtev) {
+        if (mHasPerformedLongPress) {
+            // Consume all move events following a successful long press.
+            return;
+        }
+
         int pointerIndex = ev.findPointerIndex(mActivePointerId);
         if (pointerIndex == -1) {
             pointerIndex = 0;
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 617d3dd..3a61fcd 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2872,6 +2872,7 @@
         protected PopupWindow mPopupWindow;
         protected ViewGroup mContentView;
         int mPositionX, mPositionY;
+        int mClippingLimitLeft, mClippingLimitRight;
 
         protected abstract void createPopupWindow();
         protected abstract void initContentView();
@@ -2939,8 +2940,9 @@
             // Horizontal clipping
             final DisplayMetrics displayMetrics = mTextView.getResources().getDisplayMetrics();
             final int width = mContentView.getMeasuredWidth();
-            positionX = Math.min(displayMetrics.widthPixels - width, positionX);
-            positionX = Math.max(0, positionX);
+            positionX = Math.min(
+                    displayMetrics.widthPixels - width + mClippingLimitRight, positionX);
+            positionX = Math.max(-mClippingLimitLeft, positionX);
 
             if (isShowing()) {
                 mPopupWindow.update(positionX, positionY, -1, -1);
@@ -3118,6 +3120,8 @@
         private TextView mAddToDictionaryButton;
         private TextView mDeleteButton;
         private SuggestionSpan mMisspelledSpan;
+        private int mContainerMarginWidth;
+        private int mContainerMarginTop;
 
         private class CustomPopupWindow extends PopupWindow {
             @Override
@@ -3155,10 +3159,20 @@
         protected void initContentView() {
             final LayoutInflater inflater = (LayoutInflater) mTextView.getContext().
                     getSystemService(Context.LAYOUT_INFLATER_SERVICE);
-            final LinearLayout linearLayout = (LinearLayout) inflater.inflate(
+            final ViewGroup relativeLayout = (ViewGroup) inflater.inflate(
                     mTextView.mTextEditSuggestionContainerLayout, null);
 
-            final ListView suggestionListView = (ListView) linearLayout.findViewById(
+            final LinearLayout suggestionWindowContainer =
+                    (LinearLayout) relativeLayout.findViewById(
+                            com.android.internal.R.id.suggestionWindowContainer);
+            ViewGroup.MarginLayoutParams lp =
+                    (ViewGroup.MarginLayoutParams) suggestionWindowContainer.getLayoutParams();
+            mContainerMarginWidth = lp.leftMargin + lp.rightMargin;
+            mContainerMarginTop = lp.topMargin;
+            mClippingLimitLeft = lp.leftMargin;
+            mClippingLimitRight = lp.rightMargin;
+
+            final ListView suggestionListView = (ListView) relativeLayout.findViewById(
                     com.android.internal.R.id.suggestionContainer);
 
             mSuggestionsAdapter = new SuggestionAdapter();
@@ -3171,9 +3185,9 @@
                 mSuggestionInfos[i] = new SuggestionInfo();
             }
 
-            mContentView = linearLayout;
+            mContentView = relativeLayout;
 
-            mAddToDictionaryButton = (TextView) linearLayout.findViewById(
+            mAddToDictionaryButton = (TextView) relativeLayout.findViewById(
                     com.android.internal.R.id.addToDictionaryButton);
             mAddToDictionaryButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
@@ -3197,7 +3211,7 @@
                 }
             });
 
-            mDeleteButton = (TextView) linearLayout.findViewById(
+            mDeleteButton = (TextView) relativeLayout.findViewById(
                     com.android.internal.R.id.deleteButton);
             mDeleteButton.setOnClickListener(new View.OnClickListener() {
                 public void onClick(View v) {
@@ -3306,6 +3320,8 @@
             mDeleteButton.measure(horizontalMeasure, verticalMeasure);
             width = Math.max(width, mDeleteButton.getMeasuredWidth());
 
+            width += mContainerMarginWidth;
+
             // Enforce the width based on actual text widths
             mContentView.measure(
                     View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
@@ -3327,7 +3343,7 @@
 
         @Override
         protected int getVerticalLocalPosition(int line) {
-            return mTextView.getLayout().getLineBottom(line);
+            return mTextView.getLayout().getLineBottom(line) - mContainerMarginTop;
         }
 
         @Override
diff --git a/core/java/com/android/internal/app/LocaleHelper.java b/core/java/com/android/internal/app/LocaleHelper.java
index 71c2c21..c7459d7 100644
--- a/core/java/com/android/internal/app/LocaleHelper.java
+++ b/core/java/com/android/internal/app/LocaleHelper.java
@@ -17,6 +17,7 @@
 package com.android.internal.app;
 
 import android.icu.util.ULocale;
+import android.icu.text.ListFormatter;
 import android.util.LocaleList;
 
 import java.text.Collator;
@@ -145,20 +146,16 @@
      * @return the locale aware list of locale names
      */
     public static String getDisplayLocaleList(LocaleList locales, Locale displayLocale) {
-        final StringBuilder result = new StringBuilder();
-
         final Locale dispLocale = displayLocale == null ? Locale.getDefault() : displayLocale;
+
         int localeCount = locales.size();
+        final String[] localeNames = new String[localeCount];
         for (int i = 0; i < localeCount; i++) {
-            Locale locale = locales.get(i);
-            result.append(LocaleHelper.getDisplayName(locale, dispLocale, false));
-            // TODO: language aware list formatter. ICU has one.
-            if (i < localeCount - 1) {
-                result.append(", ");
-            }
+            localeNames[i] = LocaleHelper.getDisplayName(locales.get(i), dispLocale, false);
         }
 
-        return result.toString();
+        ListFormatter lfn = ListFormatter.getInstance(dispLocale);
+        return lfn.format(localeNames);
     }
 
     /**
diff --git a/core/java/com/android/internal/app/UnlaunchableAppActivity.java b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
index aada6e3..29190f9 100644
--- a/core/java/com/android/internal/app/UnlaunchableAppActivity.java
+++ b/core/java/com/android/internal/app/UnlaunchableAppActivity.java
@@ -32,6 +32,7 @@
 import android.os.Bundle;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.text.TextUtils;
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -69,12 +70,11 @@
         }
 
         String dialogTitle;
-        String dialogMessage;
+        String dialogMessage = null;
         if (mReason == UNLAUNCHABLE_REASON_QUIET_MODE) {
             dialogTitle = getResources().getString(R.string.work_mode_off_title);
             dialogMessage = getResources().getString(R.string.work_mode_off_message);
         } else if (mReason == UNLAUNCHABLE_REASON_SUSPENDED_PACKAGE) {
-            PackageManager pm = getPackageManager();
             DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(
                     Context.DEVICE_POLICY_SERVICE);
             String packageName = intent.getStringExtra(Intent.EXTRA_PACKAGE_NAME);
@@ -91,12 +91,19 @@
             }
             dialogTitle = String.format(getResources().getString(R.string.suspended_package_title),
                     packageLabel);
-            dialogMessage = dpm.getShortSupportMessageForUser(dpm.getProfileOwnerAsUser(mUserId),
-                    mUserId);
-            if (dialogMessage == null) {
-                dialogMessage = String.format(
-                        getResources().getString(R.string.suspended_package_message),
-                        dpm.getProfileOwnerNameAsUser(mUserId));
+            ComponentName profileOwner = dpm.getProfileOwnerAsUser(mUserId);
+            String profileOwnerName = null;
+            if (profileOwner != null) {
+                dialogMessage = dpm.getShortSupportMessageForUser(profileOwner, mUserId);
+                profileOwnerName = dpm.getProfileOwnerNameAsUser(mUserId);
+            }
+            // Fall back to standard message if profile owner hasn't set something specific.
+            if (TextUtils.isEmpty(dialogMessage)) {
+                if (TextUtils.isEmpty(profileOwnerName)) {
+                    profileOwnerName = getResources().getString(R.string.unknownName);
+                }
+                dialogMessage = getResources().getString(R.string.suspended_package_message,
+                        profileOwnerName);
             }
         } else {
             Log.wtf(TAG, "Invalid unlaunchable type: " + mReason);
diff --git a/core/java/com/android/internal/widget/FloatingToolbar.java b/core/java/com/android/internal/widget/FloatingToolbar.java
index 976ef4b..480d806 100644
--- a/core/java/com/android/internal/widget/FloatingToolbar.java
+++ b/core/java/com/android/internal/widget/FloatingToolbar.java
@@ -920,14 +920,14 @@
                     mOverflowPanel.setY(mOverflowButtonSize.getHeight());  // align bottom
                 }
             } else {
-                if (hasOverflow()) {
-                    // overflow not open. Set closed state.
-                    final Size containerSize = mMainPanelSize;
-                    setSize(mContentContainer, containerSize);
-                    mMainPanel.setAlpha(1);
-                    mOverflowPanel.setAlpha(0);
-                    mOverflowButton.setImageDrawable(mOverflow);
+                // Overflow not open. Set closed state.
+                final Size containerSize = mMainPanelSize;
+                setSize(mContentContainer, containerSize);
+                mMainPanel.setAlpha(1);
+                mOverflowPanel.setAlpha(0);
+                mOverflowButton.setImageDrawable(mOverflow);
 
+                if (hasOverflow()) {
                     // Update x-coordinates depending on RTL state.
                     if (isRTL()) {
                         mContentContainer.setX(mMarginHorizontal);  // align left
@@ -960,8 +960,11 @@
                         mOverflowPanel.setY(mOverflowButtonSize.getHeight());  // align bottom
                     }
                 } else {
-                    mContentContainer.setX(mMarginHorizontal);
-                    mContentContainer.setY(mMarginVertical);
+                    // No overflow.
+                    mContentContainer.setX(mMarginHorizontal);  // align left
+                    mContentContainer.setY(mMarginVertical);  // align top
+                    mMainPanel.setX(0);  // align left
+                    mMainPanel.setY(0);  // align top
                 }
             }
         }
@@ -1092,6 +1095,7 @@
             final LinkedList<MenuItem> remainingMenuItems = new LinkedList<MenuItem>(menuItems);
 
             mMainPanel.removeAllViews();
+            mMainPanel.setPaddingRelative(0, 0, 0, 0);
 
             boolean isFirstItem = true;
             while (!remainingMenuItems.isEmpty()) {
@@ -1302,7 +1306,6 @@
             overflowButton.setOnClickListener(new View.OnClickListener() {
                 @Override
                 public void onClick(View v) {
-                    final Drawable drawable = overflowButton.getDrawable();
                     if (mIsOverflowOpen) {
                         overflowButton.setImageDrawable(mToOverflow);
                         mToOverflow.start();
@@ -1599,6 +1602,8 @@
     private static ViewGroup createContentContainer(Context context) {
         ViewGroup contentContainer = (ViewGroup) LayoutInflater.from(context)
                 .inflate(R.layout.floating_popup_container, null);
+        contentContainer.setLayoutParams(new ViewGroup.LayoutParams(
+                ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
         contentContainer.setTag(FLOATING_TOOLBAR_TAG);
         return contentContainer;
     }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index 3f468ac..ba456f9 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -17,7 +17,6 @@
 package com.android.internal.widget;
 
 import android.annotation.IntDef;
-import android.app.ActivityManager;
 import android.app.admin.DevicePolicyManager;
 import android.app.trust.IStrongAuthTracker;
 import android.app.trust.TrustManager;
@@ -503,10 +502,9 @@
         if (userHandle == UserHandle.USER_SYSTEM) {
             // Set the encryption password to default.
             updateEncryptionPassword(StorageManager.CRYPT_TYPE_DEFAULT, null);
+            setCredentialRequiredToDecrypt(false);
         }
 
-        setCredentialRequiredToDecrypt(false);
-
         getDevicePolicyManager().setActivePasswordState(
                 DevicePolicyManager.PASSWORD_QUALITY_UNSPECIFIED, 0, 0, 0, 0, 0, 0, 0, userHandle);
 
@@ -1340,9 +1338,9 @@
     }
 
     public void setCredentialRequiredToDecrypt(boolean required) {
-        if (ActivityManager.getCurrentUser() != UserHandle.USER_SYSTEM) {
-            Log.w(TAG, "Only device owner may call setCredentialRequiredForDecrypt()");
-            return;
+        if (!(getUserManager().isSystemUser() || getUserManager().isPrimaryUser())) {
+            throw new IllegalStateException(
+                    "Only the system or primary user may call setCredentialRequiredForDecrypt()");
         }
 
         if (isDeviceEncryptionEnabled()){
diff --git a/core/java/com/android/internal/widget/MediaNotificationView.java b/core/java/com/android/internal/widget/MediaNotificationView.java
new file mode 100644
index 0000000..b45fd06
--- /dev/null
+++ b/core/java/com/android/internal/widget/MediaNotificationView.java
@@ -0,0 +1,136 @@
+/*
+ * Copyright (C) 2016 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.widget;
+
+import android.annotation.Nullable;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ImageView;
+import android.widget.RelativeLayout;
+import android.widget.RemoteViews;
+
+/**
+ * A TextView that can float around an image on the end.
+ *
+ * @hide
+ */
+@RemoteViews.RemoteView
+public class MediaNotificationView extends RelativeLayout {
+
+    private final int mMaxImageSize;
+    private final int mImageMarginBottom;
+    private final int mImageMinTopMargin;
+    private final int mNotificationContentMarginEnd;
+    private final int mNotificationContentImageMarginEnd;
+    private ImageView mRightIcon;
+    private View mActions;
+    private View mHeader;
+
+    public MediaNotificationView(Context context) {
+        this(context, null);
+    }
+
+    public MediaNotificationView(Context context, @Nullable AttributeSet attrs) {
+        this(context, attrs, 0);
+    }
+
+    public MediaNotificationView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int mode = MeasureSpec.getMode(widthMeasureSpec);
+        boolean hasIcon = mRightIcon.getVisibility() != GONE;
+        if (hasIcon && mode != MeasureSpec.UNSPECIFIED) {
+            measureChild(mActions, widthMeasureSpec, heightMeasureSpec);
+            int size = MeasureSpec.getSize(widthMeasureSpec);
+            int height = MeasureSpec.getSize(heightMeasureSpec);
+            size = size - mActions.getMeasuredWidth();
+            ViewGroup.MarginLayoutParams layoutParams =
+                    (MarginLayoutParams) mRightIcon.getLayoutParams();
+            size -= layoutParams.getMarginEnd();
+            size = Math.min(size, mMaxImageSize);
+            size = Math.max(size, mRightIcon.getMinimumWidth());
+            layoutParams.width = size;
+            layoutParams.height = size;
+            // because we can't allign it to the bottom with a margin, we add a topmargin to it
+            layoutParams.topMargin = height - size - mImageMarginBottom;
+            // If the topMargin is high enough we can also remove the header constraint!
+            if (layoutParams.topMargin >= mImageMinTopMargin) {
+                resetHeaderIndention();
+            } else {
+                int paddingEnd = mNotificationContentImageMarginEnd;
+                ViewGroup.MarginLayoutParams headerParams =
+                        (MarginLayoutParams) mHeader.getLayoutParams();
+                headerParams.setMarginEnd(size + layoutParams.getMarginEnd());
+                if (mHeader.getPaddingEnd() != paddingEnd) {
+                    mHeader.setPadding(
+                            isLayoutRtl() ? paddingEnd : mHeader.getPaddingLeft(),
+                            mHeader.getPaddingTop(),
+                            isLayoutRtl() ? mHeader.getPaddingLeft() : paddingEnd,
+                            mHeader.getPaddingBottom());
+                    mHeader.setLayoutParams(headerParams);
+                }
+            }
+            mRightIcon.setLayoutParams(layoutParams);
+        } else if (!hasIcon && mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
+            resetHeaderIndention();
+        }
+        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
+    }
+
+    private void resetHeaderIndention() {
+        if (mHeader.getPaddingEnd() != mNotificationContentMarginEnd) {
+            ViewGroup.MarginLayoutParams headerParams =
+                    (MarginLayoutParams) mHeader.getLayoutParams();
+            headerParams.setMarginEnd(0);
+            mHeader.setPadding(
+                    isLayoutRtl() ? mNotificationContentMarginEnd : mHeader.getPaddingLeft(),
+                    mHeader.getPaddingTop(),
+                    isLayoutRtl() ? mHeader.getPaddingLeft() : mNotificationContentMarginEnd,
+                    mHeader.getPaddingBottom());
+            mHeader.setLayoutParams(headerParams);
+        }
+    }
+
+    public MediaNotificationView(Context context, AttributeSet attrs, int defStyleAttr,
+            int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        mMaxImageSize = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.media_notification_expanded_image_max_size);
+        mImageMarginBottom = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.media_notification_expanded_image_margin_bottom);
+        mImageMinTopMargin = (int) (context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin_top)
+                + getResources().getDisplayMetrics().density * 2);
+        mNotificationContentMarginEnd = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin_end);
+        mNotificationContentImageMarginEnd = context.getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_image_margin_end);
+    }
+
+    @Override
+    protected void onFinishInflate() {
+        super.onFinishInflate();
+        mRightIcon = (ImageView) findViewById(com.android.internal.R.id.right_icon);
+        mActions = findViewById(com.android.internal.R.id.media_actions);
+        mHeader = findViewById(com.android.internal.R.id.notification_header);
+    }
+}
diff --git a/core/jni/android_media_AudioRecord.cpp b/core/jni/android_media_AudioRecord.cpp
index b977e37..d25da78 100644
--- a/core/jni/android_media_AudioRecord.cpp
+++ b/core/jni/android_media_AudioRecord.cpp
@@ -54,6 +54,10 @@
 };
 static audio_attributes_fields_t javaAudioAttrFields;
 static audio_record_fields_t     javaAudioRecordFields;
+static struct {
+    jfieldID  fieldFramePosition;     // AudioTimestamp.framePosition
+    jfieldID  fieldNanoTime;          // AudioTimestamp.nanoTime
+} javaAudioTimestampFields;
 
 struct audiorecord_callback_cookie {
     jclass      audioRecord_class;
@@ -678,7 +682,40 @@
     }
 }
 
+// ----------------------------------------------------------------------------
+static jint android_media_AudioRecord_get_timestamp(JNIEnv *env, jobject thiz,
+        jobject timestamp, jint timebase) {
+    sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
 
+    if (lpRecorder == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+            "Unable to retrieve AudioRecord pointer for getTimestamp()");
+        return (jint)AUDIO_JAVA_ERROR;
+    }
+
+    // TODO Enable.
+#if 0
+    // get the record timestamp
+    ExtendedTimestamp ts;
+    jint status = nativeToJavaStatus(lpRecorder->getExtendedTimestamp(&ts));
+
+    if (status == AUDIO_JAVA_SUCCESS) {
+        // set the data
+        int64_t position, time;
+
+        status = nativeToJavaStatus(ts.getBestTimestamp(&position, &time, timebase));
+        if (status == AUDIO_JAVA_SUCCESS) {
+            env->SetLongField(
+                    timestamp, javaAudioTimestampFields.fieldFramePosition, position);
+            env->SetLongField(
+                    timestamp, javaAudioTimestampFields.fieldNanoTime, time);
+        }
+    }
+    return status;
+#else
+    return (jint)AUDIO_JAVA_INVALID_OPERATION;
+#endif
+}
 
 // ----------------------------------------------------------------------------
 // ----------------------------------------------------------------------------
@@ -716,6 +753,8 @@
     {"native_enableDeviceCallback", "()V", (void *)android_media_AudioRecord_enableDeviceCallback},
     {"native_disableDeviceCallback", "()V",
                                         (void *)android_media_AudioRecord_disableDeviceCallback},
+    {"native_get_timestamp", "(Landroid/media/AudioTimestamp;I)I",
+                                       (void *)android_media_AudioRecord_get_timestamp},
 };
 
 // field names found in android/media/AudioRecord.java
@@ -758,6 +797,13 @@
     javaAudioAttrFields.fieldFormattedTags = GetFieldIDOrDie(env,
             audioAttrClass, "mFormattedTags", "Ljava/lang/String;");
 
+    // Get the RecordTimestamp class and fields
+    jclass audioTimestampClass = FindClassOrDie(env, "android/media/AudioTimestamp");
+    javaAudioTimestampFields.fieldFramePosition =
+            GetFieldIDOrDie(env, audioTimestampClass, "framePosition", "J");
+    javaAudioTimestampFields.fieldNanoTime =
+            GetFieldIDOrDie(env, audioTimestampClass, "nanoTime", "J");
+
     return RegisterMethodsOrDie(env, kClassPathName, gMethods, NELEM(gMethods));
 }
 
diff --git a/core/res/res/layout/notification_template_material_big_media.xml b/core/res/res/layout/notification_template_material_big_media.xml
index e8ff186..aa78eff 100644
--- a/core/res/res/layout/notification_template_material_big_media.xml
+++ b/core/res/res/layout/notification_template_material_big_media.xml
@@ -16,17 +16,17 @@
   -->
 
 <!-- Layout for the expanded media notification -->
-<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<com.android.internal.widget.MediaNotificationView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/status_bar_latest_event_content"
     android:layout_width="match_parent"
-    android:layout_height="128dp"
+    android:layout_height="126dp"
     android:background="#00000000"
     android:tag="bigMediaNarrow"
     >
     <include layout="@layout/notification_template_header"
-        android:layout_width="fill_parent"
+        android:layout_width="match_parent"
         android:layout_height="48dp"
-        android:layout_marginEnd="106dp"/>
+        android:layout_alignParentStart="true"/>
     <LinearLayout
         android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
@@ -34,7 +34,7 @@
         android:layout_marginTop="@dimen/notification_content_margin_top"
         android:layout_marginStart="@dimen/notification_content_margin_start"
         android:layout_marginBottom="@dimen/notification_content_margin_bottom"
-        android:layout_marginEnd="24dp"
+        android:layout_marginEnd="@dimen/notification_content_margin_end"
         android:layout_toStartOf="@id/right_icon"
         android:minHeight="@dimen/notification_min_content_height"
         android:orientation="vertical"
@@ -57,12 +57,13 @@
     </LinearLayout>
 
     <ImageView android:id="@+id/right_icon"
-        android:layout_width="96dp"
-        android:layout_height="96dp"
+        android:layout_width="@dimen/media_notification_expanded_image_max_size"
+        android:layout_height="@dimen/media_notification_expanded_image_max_size"
+        android:minWidth="40dp"
         android:layout_marginEnd="16dp"
         android:layout_marginTop="16dp"
         android:layout_alignParentEnd="true"
         android:layout_alignParentTop="true"
         android:scaleType="centerCrop"
         />
-</RelativeLayout>
+</com.android.internal.widget.MediaNotificationView>
diff --git a/core/res/res/layout/notification_template_material_media.xml b/core/res/res/layout/notification_template_material_media.xml
index 9fcd356..aea9b44 100644
--- a/core/res/res/layout/notification_template_material_media.xml
+++ b/core/res/res/layout/notification_template_material_media.xml
@@ -24,8 +24,7 @@
     >
     <include layout="@layout/notification_template_header"
         android:layout_width="fill_parent"
-        android:layout_height="48dp"
-        android:layout_marginEnd="106dp"/>
+        android:layout_height="48dp" />
     <LinearLayout
         android:id="@+id/notification_main_column"
         android:layout_width="match_parent"
@@ -34,7 +33,6 @@
         android:orientation="horizontal"
         android:layout_marginStart="@dimen/notification_content_margin_start"
         android:layout_marginTop="@dimen/notification_content_margin_top"
-        android:layout_marginEnd="72dp"
         android:tag="media"
         >
         <LinearLayout
diff --git a/core/res/res/layout/text_edit_suggestion_container.xml b/core/res/res/layout/text_edit_suggestion_container.xml
index fe02d4e..17e93d0 100644
--- a/core/res/res/layout/text_edit_suggestion_container.xml
+++ b/core/res/res/layout/text_edit_suggestion_container.xml
@@ -14,32 +14,41 @@
      limitations under the License.
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:background="@drawable/text_edit_suggestions_window"
-    android:dropDownSelector="@drawable/list_selector_background"
-    android:divider="@null">
-    <ListView
-        android:id="@+id/suggestionContainer"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:divider="?android:attr/dividerHorizontal">
-        <!-- Suggestions will be added here. -->
-    </ListView>
-
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
     <LinearLayout
-        android:layout_width="match_parent"
+        android:id="@+id/suggestionWindowContainer"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:orientation="vertical"
-        android:divider="?android:attr/dividerHorizontal"
-        android:showDividers="middle">
-        <TextView
-            style="@android:style/Widget.Holo.SuggestionButton"
-            android:id="@+id/addToDictionaryButton"
-            android:text="@string/addToDictionary" />
-        <TextView
-            style="@android:style/Widget.Holo.SuggestionButton"
-            android:id="@+id/deleteButton"
-            android:text="@string/deleteText" />
+        android:elevation="2dp"
+        android:layout_margin="20dp"
+        android:background="@drawable/text_edit_suggestions_window"
+        android:dropDownSelector="@drawable/list_selector_background"
+        android:divider="@null">
+        <ListView
+            android:id="@+id/suggestionContainer"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:divider="?android:attr/dividerHorizontal">
+            <!-- Suggestions will be added here. -->
+        </ListView>
+
+        <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:orientation="vertical"
+            android:divider="?android:attr/dividerHorizontal"
+            android:showDividers="middle">
+            <TextView
+                style="@android:style/Widget.Holo.SuggestionButton"
+                android:id="@+id/addToDictionaryButton"
+                android:text="@string/addToDictionary" />
+            <TextView
+                style="@android:style/Widget.Holo.SuggestionButton"
+                android:id="@+id/deleteButton"
+                android:text="@string/deleteText" />
+        </LinearLayout>
     </LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/layout/text_edit_suggestion_container_material.xml b/core/res/res/layout/text_edit_suggestion_container_material.xml
index 62e315b4..7826803 100644
--- a/core/res/res/layout/text_edit_suggestion_container_material.xml
+++ b/core/res/res/layout/text_edit_suggestion_container_material.xml
@@ -16,29 +16,38 @@
 
 <!-- Background of the popup window is the same as the one of the floating toolbar.
      Use floating toolbar background style. -->
-<LinearLayout  xmlns:android="http://schemas.android.com/apk/res/android"
-    android:orientation="vertical"
-    android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
-    android:divider="?android:attr/listDivider"
-    android:showDividers="middle" >
-    <ListView
-        android:id="@+id/suggestionContainer"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:paddingTop="8dip"
-        android:paddingBottom="0dip"
-        android:divider="@null" />
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="wrap_content"
+    android:layout_height="wrap_content">
     <LinearLayout
-        android:layout_width="match_parent"
+        android:id="@+id/suggestionWindowContainer"
+        android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:orientation="vertical">
-          <TextView
-              style="@android:style/Widget.Material.SuggestionButton"
-              android:id="@+id/addToDictionaryButton"
-              android:text="@string/addToDictionary" />
-          <TextView
-              style="@android:style/Widget.Material.SuggestionButton"
-              android:id="@+id/deleteButton"
-              android:text="@string/deleteText" />
+        android:background="?android:attr/floatingToolbarPopupBackgroundDrawable"
+        android:elevation="2dp"
+        android:layout_margin="20dp"
+        android:orientation="vertical"
+        android:divider="?android:attr/listDivider"
+        android:showDividers="middle">
+        <ListView
+            android:id="@+id/suggestionContainer"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingTop="8dp"
+            android:paddingBottom="0dp"
+            android:divider="@null" />
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="vertical">
+            <TextView
+                style="@android:style/Widget.Material.SuggestionButton"
+                android:id="@+id/addToDictionaryButton"
+                android:text="@string/addToDictionary" />
+            <TextView
+                style="@android:style/Widget.Material.SuggestionButton"
+                android:id="@+id/deleteButton"
+                android:text="@string/deleteText" />
+        </LinearLayout>
     </LinearLayout>
-</LinearLayout>
+</RelativeLayout>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index f92e7f0..7c6f338 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -146,6 +146,9 @@
     <!-- The margin on the end of the content view with a picture.-->
     <dimen name="notification_content_picture_margin">56dp</dimen>
 
+    <!-- The margin on the end of the content view with a picture in the compact media.-->
+    <dimen name="notification_content_picture_margin_media">72dp</dimen>
+
     <!-- height of the content margin to accomodate for the header -->
     <dimen name="notification_content_margin_top">30dp</dimen>
 
@@ -169,6 +172,15 @@
     <!-- The minimum height of the content if there are at least two lines or a picture-->
     <dimen name="notification_min_content_height">41dp</dimen>
 
+    <!-- The maximum size of the image in the expanded media notification -->
+    <dimen name="media_notification_expanded_image_max_size">94dp</dimen>
+
+    <!-- The maximum size of the image in the expanded media notification -->
+    <dimen name="media_notification_expanded_image_margin_bottom">16dp</dimen>
+
+    <!-- The margin of the content to an image-->
+    <dimen name="notification_content_image_margin_end">8dp</dimen>
+
     <!-- Preferred width of the search view. -->
     <dimen name="search_view_preferred_width">320dip</dimen>
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index b2eab4c..26421fb 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4191,10 +4191,10 @@
     <string name="new_sms_notification_content">Open SMS app to view</string>
 
     <!-- Notification title shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
-    <string name="user_encrypted_title">Device encrypted</string>
+    <string name="user_encrypted_title">Some functions might not be available</string>
     <!-- Notification message shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
-    <string name="user_encrypted_message">Some functions might not be available</string>
+    <string name="user_encrypted_message">Touch to continue</string>
     <!-- Notification detail shown when user profile is credential encrypted and requires the user to unlock before some features are usable [CHAR LIMIT=30] -->
-    <string name="user_encrypted_detail">Touch to continue</string>
+    <string name="user_encrypted_detail">User profile locked</string>
 
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index aa44d7c..74ca8a5 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2388,6 +2388,7 @@
   <java-symbol type="color" name="system_bar_background_semi_transparent" />
 
   <!-- EditText suggestion popup. -->
+  <java-symbol type="id" name="suggestionWindowContainer" />
   <java-symbol type="id" name="suggestionContainer" />
   <java-symbol type="id" name="addToDictionaryButton" />
   <java-symbol type="id" name="deleteButton" />
@@ -2503,6 +2504,11 @@
   <java-symbol type="string" name="new_sms_notification_title" />
   <java-symbol type="string" name="new_sms_notification_content" />
 
+  <java-symbol type="dimen" name="media_notification_expanded_image_max_size" />
+  <java-symbol type="dimen" name="media_notification_expanded_image_margin_bottom" />
+  <java-symbol type="dimen" name="notification_content_image_margin_end" />
+  <java-symbol type="dimen" name="notification_content_picture_margin_media" />
+
   <java-symbol type="bool" name="config_strongAuthRequiredOnBoot" />
 
   <!-- Encryption notification while accounts are locked by credential encryption -->
diff --git a/media/java/android/media/AudioRecord.java b/media/java/android/media/AudioRecord.java
index 7c21893..800b914 100644
--- a/media/java/android/media/AudioRecord.java
+++ b/media/java/android/media/AudioRecord.java
@@ -826,6 +826,33 @@
     }
 
     /**
+     * Poll for an {@link AudioTimestamp} on demand.
+     * <p>
+     * The AudioTimestamp reflects the frame delivery information at
+     * the earliest point available in the capture pipeline.
+     * <p>
+     * Calling {@link #startRecording()} following a {@link #stop()} will reset
+     * the frame count to 0.
+     *
+     * @param timestamp a reference to a non-null AudioTimestamp instance.
+     * @param timebase one of
+     *        {@link AudioTimestamp#TIMEBASE_BOOTTIME AudioTimestamp.TIMEBASE_BOOTTIME} or
+     *        {@link AudioTimestamp#TIMEBASE_MONOTONIC AudioTimestamp.TIMEBASE_MONOTONIC}.
+     * @return {@link #SUCCESS} if a timestamp is available,
+     *         or {@link #ERROR_INVALID_OPERATION} if a timestamp not available.
+     */
+     public int getTimestamp(@NonNull AudioTimestamp timestamp,
+             @AudioTimestamp.Timebase int timebase)
+     {
+         if (timestamp == null ||
+                 (timebase != AudioTimestamp.TIMEBASE_BOOTTIME
+                 && timebase != AudioTimestamp.TIMEBASE_MONOTONIC)) {
+             throw new IllegalArgumentException();
+         }
+         return native_get_timestamp(timestamp, timebase);
+     }
+
+    /**
      * Returns the minimum buffer size required for the successful creation of an AudioRecord
      * object, in byte units.
      * Note that this size doesn't guarantee a smooth recording under load, and higher values
@@ -1709,6 +1736,9 @@
     private native final void native_enableDeviceCallback();
     private native final void native_disableDeviceCallback();
 
+    private native final int native_get_timestamp(@NonNull AudioTimestamp timestamp,
+            @AudioTimestamp.Timebase int timebase);
+
     //---------------------------------------------------------
     // Utility methods
     //------------------
diff --git a/media/java/android/media/AudioTimestamp.java b/media/java/android/media/AudioTimestamp.java
index 965ba85..be8ca15 100644
--- a/media/java/android/media/AudioTimestamp.java
+++ b/media/java/android/media/AudioTimestamp.java
@@ -16,29 +16,74 @@
 
 package android.media;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+import android.annotation.IntDef;
+
 /**
  * Structure that groups a position in frame units relative to an assumed audio stream,
- * together with the estimated time when that frame was presented or is committed to be
- * presented.
- * In the case of audio output, "present" means that audio produced on device
- * is detectable by an external observer off device.
+ * together with the estimated time when that frame enters or leaves the audio
+ * processing pipeline on that device. This can be used to coordinate events
+ * and interactions with the external environment.
+ * <p>
  * The time is based on the implementation's best effort, using whatever knowledge
  * is available to the system, but cannot account for any delay unknown to the implementation.
  *
- * @see AudioTrack#getTimestamp
+ * @see AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)
+ * @see AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)
  */
 public final class AudioTimestamp
 {
     /**
+     * Clock monotonic or its equivalent on the system,
+     * in the same units and timebase as {@link java.lang.System#nanoTime}.
+     */
+    public static final int TIMEBASE_MONOTONIC = 0;
+
+    /**
+     * Clock monotonic including suspend time or its equivalent on the system,
+     * in the same units and timebase as {@link android.os.SystemClock#elapsedRealtimeNanos}.
+     */
+    public static final int TIMEBASE_BOOTTIME = 1;
+
+    /** @hide */
+    @IntDef({
+        TIMEBASE_MONOTONIC,
+        TIMEBASE_BOOTTIME,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Timebase {}
+
+    /**
      * Position in frames relative to start of an assumed audio stream.
-     * The low-order 32 bits of position is in wrapping frame units similar to
-     * {@link AudioTrack#getPlaybackHeadPosition}.
+     * <p>
+     * When obtained through
+     * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)},
+     * all 64 bits of position are valid.
+     * <p>
+     * When obtained through
+     * {@link AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)},
+     * the low-order 32 bits of position is in wrapping frame units similar to
+     * {@link AudioTrack#getPlaybackHeadPosition AudioTrack.getPlaybackHeadPosition()}.
      */
     public long framePosition;
 
     /**
-     * The estimated time when frame was presented or is committed to be presented,
-     * in the same units and timebase as {@link java.lang.System#nanoTime}.
+     * Time associated with the frame in the audio pipeline.
+     * <p>
+     * When obtained through
+     * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)},
+     * this is the estimated time in nanoseconds when the frame referred to by
+     * {@link #framePosition} was captured. The timebase is either
+     * {@link #TIMEBASE_MONOTONIC} or {@link #TIMEBASE_BOOTTIME}, depending
+     * on the timebase parameter used in
+     * {@link AudioRecord#getTimestamp AudioRecord.getTimestamp(AudioTimestamp, int)}.
+     * <p>
+     * When obtained through
+     * {@link AudioTrack#getTimestamp AudioTrack.getTimestamp(AudioTimestamp)},
+     * this is the estimated time when the frame was presented or is committed to be presented,
+     * with a timebase of {@link #TIMEBASE_MONOTONIC}.
      */
     public long nanoTime;
 }
diff --git a/media/java/android/media/browse/MediaBrowser.java b/media/java/android/media/browse/MediaBrowser.java
index 869512d..93e6dac 100644
--- a/media/java/android/media/browse/MediaBrowser.java
+++ b/media/java/android/media/browse/MediaBrowser.java
@@ -473,8 +473,9 @@
         // the service will be told when we connect.
         if (mState == CONNECT_STATE_CONNECTED) {
             try {
-                // NOTE: In order not to break the behavior of the support library, call
-                // addSubscription instead of addSubscriptionWithOptions when the options are null.
+                // NOTE: Do not call addSubscriptionWithOptions when options are null. Otherwise,
+                // it will break the action of support library which expects addSubscription will
+                // be called when options are null.
                 if (options == null) {
                     mServiceBinder.addSubscription(parentId, mServiceCallbacks);
                 } else {
@@ -500,9 +501,9 @@
         // Tell the service if necessary.
         if (sub != null && sub.remove(options) && mState == CONNECT_STATE_CONNECTED) {
             try {
-                // NOTE: In order not to break the behavior of the support library, call
-                // removeSubscription instead of removeSubscriptionWithOptions when the options
-                // are null.
+                // NOTE: Do not call removeSubscriptionWithOptions when options are null. Otherwise,
+                // it will break the action of support library which expects removeSubscription will
+                // be called when options are null.
                 if (options == null) {
                     mServiceBinder.removeSubscription(parentId, mServiceCallbacks);
                 } else {
@@ -572,9 +573,9 @@
                     Subscription sub = subscriptionEntry.getValue();
                     for (Bundle options : sub.getOptionsList()) {
                         try {
-                            // NOTE: In order not to break the behavior of the support library,
-                            // call addSubscription instead of addSubscriptionWithOptions when
-                            // the options are null.
+                            // NOTE: Do not call addSubscriptionWithOptions when options are null.
+                            // Otherwise, it will break the action of support library which expects
+                            // addSubscription will be called when options are null.
                             if (options == null) {
                                 mServiceBinder.addSubscription(id, mServiceCallbacks);
                             } else {
@@ -1034,7 +1035,7 @@
          * are the initial data as requested.
          */
         @Override
-        public void onConnect(final String root, final MediaSession.Token session,
+        public void onConnect(String root, MediaSession.Token session,
                 final Bundle extras) {
             MediaBrowser mediaBrowser = mMediaBrowser.get();
             if (mediaBrowser != null) {
@@ -1054,7 +1055,12 @@
         }
 
         @Override
-        public void onLoadChildren(final String parentId, final ParceledListSlice list,
+        public void onLoadChildren(String parentId, ParceledListSlice list) {
+            onLoadChildrenWithOptions(parentId, list, null);
+        }
+
+        @Override
+        public void onLoadChildrenWithOptions(String parentId, ParceledListSlice list,
                 final Bundle options) {
             MediaBrowser mediaBrowser = mMediaBrowser.get();
             if (mediaBrowser != null) {
diff --git a/media/java/android/media/session/MediaController.java b/media/java/android/media/session/MediaController.java
index b1a51a56..3d9b60d 100644
--- a/media/java/android/media/session/MediaController.java
+++ b/media/java/android/media/session/MediaController.java
@@ -605,6 +605,7 @@
         /**
          * Request that the player start playback for a specific media id.
          *
+         * @see PlaybackState#EXTRA_PREPARE_ONLY
          * @param mediaId The id of the requested media.
          * @param extras Optional extras that can include extra information about the media item
          *               to be played.
@@ -626,6 +627,7 @@
          * An empty or null query should be treated as a request to play any
          * music.
          *
+         * @see PlaybackState#EXTRA_PREPARE_ONLY
          * @param query The search query.
          * @param extras Optional extras that can include extra information
          *            about the query.
@@ -646,6 +648,7 @@
         /**
          * Request that the player start playback for a specific {@link Uri}.
          *
+         * @see PlaybackState#EXTRA_PREPARE_ONLY
          * @param uri  The URI of the requested media.
          * @param extras Optional extras that can include extra information about the media item
          *               to be played.
diff --git a/media/java/android/media/session/MediaSession.java b/media/java/android/media/session/MediaSession.java
index e1e9b79..8c5b19c 100644
--- a/media/java/android/media/session/MediaSession.java
+++ b/media/java/android/media/session/MediaSession.java
@@ -87,6 +87,12 @@
     public static final int FLAG_HANDLES_TRANSPORT_CONTROLS = 1 << 1;
 
     /**
+     * Set this flag on the session to indicate that it can handle
+     * the {@link PlaybackState#EXTRA_PREPARE_ONLY} field.
+     */
+    public static final int FLAG_HANDLES_PREPARE_ONLY = 1 << 2;
+
+    /**
      * System only flag for a session that needs to have priority over all other
      * sessions. This flag ensures this session will receive media button events
      * regardless of the current ordering in the system.
@@ -100,6 +106,7 @@
     @IntDef(flag = true, value = {
             FLAG_HANDLES_MEDIA_BUTTONS,
             FLAG_HANDLES_TRANSPORT_CONTROLS,
+            FLAG_HANDLES_PREPARE_ONLY,
             FLAG_EXCLUSIVE_GLOBAL_PRIORITY })
     public @interface SessionFlags { }
 
diff --git a/media/java/android/media/session/PlaybackState.java b/media/java/android/media/session/PlaybackState.java
index bbe04b5..1079a1f 100644
--- a/media/java/android/media/session/PlaybackState.java
+++ b/media/java/android/media/session/PlaybackState.java
@@ -133,6 +133,21 @@
     public static final long ACTION_PLAY_FROM_URI = 1 << 13;
 
     /**
+     * Used as an optional boolean extra field in
+     * {@link MediaController.TransportControls#playFromMediaId},
+     * {@link MediaController.TransportControls#playFromSearch}, and
+     * {@link MediaController.TransportControls#playFromUri}. Value of {@code true} overrides
+     * the default behavior of starting the playback after preparing. Check
+     * {@link MediaSession#FLAG_HANDLES_PREPARE_ONLY} to see if the media session supports this.
+     *
+     * @see MediaSession#FLAG_HANDLES_PREPARE_ONLY
+     * @see MediaController.TransportControls#playFromMediaId
+     * @see MediaController.TransportControls#playFromSearch
+     * @see MediaController.TransportControls#playFromUri
+     */
+    public static final String EXTRA_PREPARE_ONLY = "android.media.session.extra.PREPARE_ONLY";
+
+    /**
      * This is the default playback state and indicates that no media has been
      * added yet, or the performer has been reset and has no content to play.
      *
diff --git a/media/java/android/media/tv/ITvInputManager.aidl b/media/java/android/media/tv/ITvInputManager.aidl
index 0febc16..d189333 100644
--- a/media/java/android/media/tv/ITvInputManager.aidl
+++ b/media/java/android/media/tv/ITvInputManager.aidl
@@ -41,6 +41,7 @@
 interface ITvInputManager {
     List<TvInputInfo> getTvInputList(int userId);
     TvInputInfo getTvInputInfo(in String inputId, int userId);
+    void setTvInputInfo(in TvInputInfo inputInfo, int userId);
     int getTvInputState(in String inputId, int userId);
 
     List<TvContentRatingSystemInfo> getTvContentRatingSystemList(int userId);
diff --git a/media/java/android/media/tv/ITvInputManagerCallback.aidl b/media/java/android/media/tv/ITvInputManagerCallback.aidl
index 3bf415b..395c9f3 100644
--- a/media/java/android/media/tv/ITvInputManagerCallback.aidl
+++ b/media/java/android/media/tv/ITvInputManagerCallback.aidl
@@ -29,5 +29,5 @@
 
     void onInputStateChanged(in String inputId, int state);
 
-    void onTvInputInfoChanged(in String inputId, in TvInputInfo TvInputInfo);
+    void onTvInputInfoChanged(in TvInputInfo TvInputInfo);
 }
diff --git a/media/java/android/media/tv/ITvInputServiceCallback.aidl b/media/java/android/media/tv/ITvInputServiceCallback.aidl
index 9f13882..74ab562 100644
--- a/media/java/android/media/tv/ITvInputServiceCallback.aidl
+++ b/media/java/android/media/tv/ITvInputServiceCallback.aidl
@@ -27,6 +27,4 @@
     void addHardwareTvInput(in int deviceId, in TvInputInfo inputInfo);
     void addHdmiTvInput(in int id, in TvInputInfo inputInfo);
     void removeTvInput(in String inputId);
-
-    void setTvInputInfo(in String inputId, in TvInputInfo inputInfo);
 }
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index f1de8fd..86bded9 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -726,12 +726,11 @@
         }
 
         /**
-         * This is called when the information about a given TV input is changed.
+         * This is called when the information about a given TV input has been changed.
          *
-         * @param inputId The ID of the TV input.
          * @param inputInfo TvInputInfo object that contains the information about the TV input.
          */
-        public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) {
+        public void onTvInputInfoChanged(TvInputInfo inputInfo) {
         }
     }
 
@@ -784,11 +783,11 @@
             });
         }
 
-        public void postTvInputInfoChanged(final String inputId, final TvInputInfo inputInfo) {
+        public void postTvInputInfoChanged(final TvInputInfo inputInfo) {
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    mCallback.onTvInputInfoChanged(inputId, inputInfo);
+                    mCallback.onTvInputInfoChanged(inputInfo);
                 }
             });
         }
@@ -1089,10 +1088,10 @@
             }
 
             @Override
-            public void onTvInputInfoChanged(String inputId, TvInputInfo inputInfo) {
+            public void onTvInputInfoChanged(TvInputInfo inputInfo) {
                 synchronized (mLock) {
                     for (TvInputCallbackRecord record : mCallbackRecords) {
-                        record.postTvInputInfoChanged(inputId, inputInfo);
+                        record.postTvInputInfoChanged(inputInfo);
                     }
                 }
             }
@@ -1143,6 +1142,23 @@
     }
 
     /**
+     * Sets a new TvInputInfo object for a given input.
+     *
+     * <p>This is called internally only by {@link TvInputService}.
+     *
+     * @param inputInfo The TvInputInfo object to set.
+     * @throws IllegalArgumentException if the argument is {@code null}.
+     */
+    void setTvInputInfo(@NonNull TvInputInfo inputInfo) {
+        Preconditions.checkNotNull(inputInfo);
+        try {
+            mService.setTvInputInfo(inputInfo, mUserId);
+        } catch (RemoteException e) {
+            throw new RuntimeException("Error trying to set " + inputInfo, e);
+        }
+    }
+
+    /**
      * Returns the state of a given TV input.
      *
      * <p>The state is one of the following:
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index f74ae66..77e81dc 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -262,16 +262,16 @@
      * <p>The system service automatically creates the TvInputInfo for each TV input based on
      * information collected from the AndroidManifest.xml, thus it is not necessary to call this
      * method unless the TV input has additional information to pass such as ability to record and
-     * tuner count.
+     * tuner count. Attempting to change information about a TV input that the calling package does
+     * not own does nothing.
      *
-     * @param inputId The ID of the TV input.
+     * @param context The application context.
      * @param inputInfo The TvInputInfo object that contains that new information.
      */
-    public final void setTvInputInfo(String inputId, TvInputInfo inputInfo) {
-        SomeArgs args = SomeArgs.obtain();
-        args.arg1 = inputId;
-        args.arg2 = inputInfo;
-        mServiceHandler.obtainMessage(ServiceHandler.DO_SET_TV_INPUT_INFO, args).sendToTarget();
+    public static final void setTvInputInfo(Context context, TvInputInfo inputInfo) {
+        TvInputManager manager = (TvInputManager) context.getSystemService(
+                Context.TV_INPUT_SERVICE);
+        manager.setTvInputInfo(inputInfo);
     }
 
     private boolean isPassthroughInput(String inputId) {
@@ -525,7 +525,7 @@
         public void notifyVideoUnavailable(final int reason) {
             if (reason < TvInputManager.VIDEO_UNAVAILABLE_REASON_START
                     || reason > TvInputManager.VIDEO_UNAVAILABLE_REASON_END) {
-                throw new IllegalArgumentException("Unknown reason: " + reason);
+                Log.e(TAG, "notifyVideoUnavailable - unknown reason: " + reason);
             }
             executeOrPostRunnableOnMainThread(new Runnable() {
                 @MainThread
@@ -1938,7 +1938,6 @@
         private static final int DO_REMOVE_HARDWARE_TV_INPUT = 5;
         private static final int DO_ADD_HDMI_TV_INPUT = 6;
         private static final int DO_REMOVE_HDMI_TV_INPUT = 7;
-        private static final int DO_SET_TV_INPUT_INFO = 8;
 
         private void broadcastAddHardwareTvInput(int deviceId, TvInputInfo inputInfo) {
             int n = mCallbacks.beginBroadcast();
@@ -1976,18 +1975,6 @@
             mCallbacks.finishBroadcast();
         }
 
-        private void broadcastSetTvInputInfo(String inputId, TvInputInfo inputInfo) {
-            int n = mCallbacks.beginBroadcast();
-            for (int i = 0; i < n; ++i) {
-                try {
-                    mCallbacks.getBroadcastItem(i).setTvInputInfo(inputId, inputInfo);
-                } catch (RemoteException e) {
-                    Log.e(TAG, "error in broadcastSetTvInputInfo", e);
-                }
-            }
-            mCallbacks.finishBroadcast();
-        }
-
         @Override
         public final void handleMessage(Message msg) {
             switch (msg.what) {
@@ -2120,16 +2107,6 @@
                     }
                     return;
                 }
-                case DO_SET_TV_INPUT_INFO: {
-                    SomeArgs args = (SomeArgs) msg.obj;
-                    String inputId = (String) args.arg1;
-                    TvInputInfo inputInfo = (TvInputInfo) args.arg2;
-                    if (inputInfo != null) {
-                        broadcastSetTvInputInfo(inputId, inputInfo);
-                    }
-                    args.recycle();
-                    return;
-                }
                 default: {
                     Log.w(TAG, "Unhandled message code: " + msg.what);
                     return;
diff --git a/media/java/android/service/media/IMediaBrowserService.aidl b/media/java/android/service/media/IMediaBrowserService.aidl
index fe7ebfa..6ca5ac5 100644
--- a/media/java/android/service/media/IMediaBrowserService.aidl
+++ b/media/java/android/service/media/IMediaBrowserService.aidl
@@ -16,7 +16,7 @@
 oneway interface IMediaBrowserService {
 
     // Warning: DO NOT CHANGE the methods signature and order of methods.
-    // The change of the order or the method signatures could break the support library.
+    // A change of the order or the method signatures could break the support library.
 
     void connect(String pkg, in Bundle rootHints, IMediaBrowserServiceCallbacks callbacks);
     void disconnect(IMediaBrowserServiceCallbacks callbacks);
diff --git a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
index dadb025..e6b0e8c 100644
--- a/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
+++ b/media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl
@@ -13,6 +13,10 @@
  * @hide
  */
 oneway interface IMediaBrowserServiceCallbacks {
+
+    // Warning: DO NOT CHANGE the methods signature and order of methods.
+    // A change of the order or the method signatures could break the support library.
+
     /**
      * Invoked when the connected has been established.
      * @param root The root media id for browsing.
@@ -22,5 +26,6 @@
      */
     void onConnect(String root, in MediaSession.Token session, in Bundle extras);
     void onConnectFailed();
-    void onLoadChildren(String mediaId, in ParceledListSlice list, in Bundle options);
+    void onLoadChildren(String mediaId, in ParceledListSlice list);
+    void onLoadChildrenWithOptions(String mediaId, in ParceledListSlice list, in Bundle options);
 }
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 6cf90d5..299b770 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -589,7 +589,14 @@
                 final ParceledListSlice<MediaBrowser.MediaItem> pls =
                         filteredList == null ? null : new ParceledListSlice<>(filteredList);
                 try {
-                    connection.callbacks.onLoadChildren(parentId, pls, options);
+                    // NOTE: Do not call onLoadChildrenWithOptions when options are null. Otherwise,
+                    // it will break the action of support library which expects onLoadChildren will
+                    // be called when options are null.
+                    if (options == null) {
+                        connection.callbacks.onLoadChildren(parentId, pls);
+                    } else {
+                        connection.callbacks.onLoadChildrenWithOptions(parentId, pls, options);
+                    }
                 } catch (RemoteException ex) {
                     // The other side is in the process of crashing.
                     Log.w(TAG, "Calling onLoadChildren() failed for id=" + parentId
diff --git a/packages/DocumentsUI/AndroidManifest.xml b/packages/DocumentsUI/AndroidManifest.xml
index c3452d5..fa9ff01 100644
--- a/packages/DocumentsUI/AndroidManifest.xml
+++ b/packages/DocumentsUI/AndroidManifest.xml
@@ -54,8 +54,7 @@
             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">
+            android:label="@string/files_label">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
                 <category android:name="android.intent.category.LAUNCHER" />
diff --git a/packages/DocumentsUI/res/values/config.xml b/packages/DocumentsUI/res/values/config.xml
index ff28e15..e8d8c8e 100644
--- a/packages/DocumentsUI/res/values/config.xml
+++ b/packages/DocumentsUI/res/values/config.xml
@@ -18,7 +18,6 @@
     <!-- Allow Advanced Devices default value to be customised -->
     <bool name="config_defaultAdvancedDevices">false</bool>
 
-    <bool name="productivity_device">true</bool>
     <!-- Intentionally unset. Vendors should set this in an overlay. -->
     <string name="trusted_quick_viewer_package"></string>
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
index 5ffc435..9309693 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/BaseActivity.java
@@ -104,7 +104,6 @@
     public void onCreate(Bundle icicle) {
         super.onCreate(icicle);
 
-        mProductivityDevice = getResources().getBoolean(R.bool.productivity_device);
         mState = (icicle != null)
                 ? icicle.<State>getParcelable(EXTRA_STATE)
                         : buildState();
diff --git a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
index 3af988d..f51f689 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/FilesActivity.java
@@ -256,9 +256,6 @@
 
         pasteFromCb.setEnabled(mClipper.hasItemsToPaste());
 
-        newWindow.setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER);
-        newWindow.setVisible(mProductivityDevice);
-
         Menus.disableHiddenItems(menu, pasteFromCb);
         return true;
     }
diff --git a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
index 112914e..959fac6 100644
--- a/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
+++ b/packages/MtpDocumentsProvider/src/com/android/mtp/MtpDatabase.java
@@ -165,22 +165,27 @@
                             cursor.close();
                         }
 
-                        long capacityBytes = 0;
-                        long availableBytes = 0;
-                        int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
-                        int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
-                        while (storageCursor.moveToNext()) {
-                            // If requested columnNames does not include COLUMN_XXX_BYTES, we don't
-                            // calculate corresponding values.
-                            if (capacityIndex != -1) {
-                                capacityBytes += cursor.getLong(capacityIndex);
+                        if (storageCursor.getCount() != 0) {
+                            long capacityBytes = 0;
+                            long availableBytes = 0;
+                            int capacityIndex = cursor.getColumnIndex(Root.COLUMN_CAPACITY_BYTES);
+                            int availableIndex = cursor.getColumnIndex(Root.COLUMN_AVAILABLE_BYTES);
+                            while (storageCursor.moveToNext()) {
+                                // If requested columnNames does not include COLUMN_XXX_BYTES, we
+                                // don't calculate corresponding values.
+                                if (capacityIndex != -1) {
+                                    capacityBytes += cursor.getLong(capacityIndex);
+                                }
+                                if (availableIndex != -1) {
+                                    availableBytes += cursor.getLong(availableIndex);
+                                }
                             }
-                            if (availableIndex != -1) {
-                                availableBytes += cursor.getLong(availableIndex);
-                            }
+                            values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
+                            values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
+                        } else {
+                            values.putNull(Root.COLUMN_CAPACITY_BYTES);
+                            values.putNull(Root.COLUMN_AVAILABLE_BYTES);
                         }
-                        values.put(Root.COLUMN_CAPACITY_BYTES, capacityBytes);
-                        values.put(Root.COLUMN_AVAILABLE_BYTES, availableBytes);
                     }
                 } finally {
                     storageCursor.close();
diff --git a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
index 97ea717..8075999 100644
--- a/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
+++ b/packages/MtpDocumentsProvider/tests/src/com/android/mtp/MtpDatabaseTest.java
@@ -899,4 +899,24 @@
         mDatabase.getMapper().stopAddingDocuments(null);
         assertEquals("1", mDatabase.getDocumentIdForDevice(100));
     }
+
+    public void testGetClosedDevice() {
+        mDatabase.getMapper().startAddingDocuments(null);
+        mDatabase.getMapper().putDeviceDocument(new MtpDeviceRecord(
+                0, "Device", /* opened is */ false , new MtpRoot[0], null, null));
+        mDatabase.getMapper().stopAddingDocuments(null);
+
+        final String[] columns = new String [] {
+                DocumentsContract.Root.COLUMN_ROOT_ID,
+                DocumentsContract.Root.COLUMN_TITLE,
+                DocumentsContract.Root.COLUMN_AVAILABLE_BYTES
+        };
+        try (final Cursor cursor = mDatabase.queryRoots(columns)) {
+            assertEquals(1, cursor.getCount());
+            assertTrue(cursor.moveToNext());
+            assertEquals(1, cursor.getLong(0));
+            assertEquals("Device", cursor.getString(1));
+            assertTrue(cursor.isNull(2));
+        }
+    }
 }
diff --git a/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
new file mode 100644
index 0000000..5a6553f
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcut_app_item.xml
@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 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
+  -->
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/keyboard_shortcuts_keyword_wrapper"
+        android:orientation="horizontal"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:paddingStart="24dp"
+        android:paddingEnd="24dp"
+        android:paddingBottom="8dp">
+    <TextView
+            android:id="@+id/keyboard_shortcuts_keyword"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:paddingEnd="12dp"
+            android:background="@android:color/white"
+            android:textColor="#D9000000"
+            android:textSize="16sp"
+            android:maxLines="5"
+            android:singleLine="false"
+            android:scrollHorizontally="false"
+            android:layout_alignParentStart="true"
+            android:minWidth="100dp"
+            android:maxWidth="260dp"/>
+    <!--TODO: introduce and use a layout that allows wrapping and right align -->
+    <LinearLayout
+            android:id="@+id/keyboard_shortcuts_item_container"
+            android:layout_toEndOf="@+id/keyboard_shortcuts_keyword"
+            android:orientation="horizontal"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:background="@android:color/white"
+            android:layout_alignParentEnd="true"
+            android:gravity="end"
+            android:textSize="14sp"
+            android:paddingStart="0dp"
+            android:paddingEnd="0dp"
+            android:scrollHorizontally="false"
+            android:minWidth="100dp"
+            android:maxWidth="260dp"/>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
new file mode 100644
index 0000000..80a478a
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_category_title.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!--
+  ~ Copyright (C) 2016 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
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="match_parent"
+          android:layout_height="match_parent"
+          android:textSize="14sp"
+          android:paddingStart="24dp"
+          android:paddingTop="20dp"
+          android:paddingEnd="24dp"
+          android:paddingBottom="13dp" />
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
new file mode 100644
index 0000000..fa07eb1
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_container.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="horizontal"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
new file mode 100644
index 0000000..5002c12
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_key_view.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 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
+  -->
+<TextView xmlns:android="http://schemas.android.com/apk/res/android"
+          android:layout_width="wrap_content"
+          android:layout_height="wrap_content"
+          android:layout_marginStart="4dp"
+          android:padding="4dp"
+          android:background="#EEEEEE"
+          android:textColor="#8C000000"
+          android:singleLine="true"
+          android:textSize="14sp"/>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
index 460433e..77b1264 100644
--- a/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_view.xml
@@ -1,6 +1,6 @@
 <?xml version="1.0" encoding="utf-8"?>
 <!--
-  ~ Copyright (C) 2015 The Android Open Source Project
+  ~ Copyright (C) 2016 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,11 +14,25 @@
   ~ See the License for the specific language governing permissions and
   ~ limitations under the License
   -->
-<RelativeLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/keyboard_shortcuts_wrapper"
-    android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginTop="40dp"
-    android:focusable="true">
-</RelativeLayout>
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:id="@+id/keyboard_shortcuts_wrapper"
+        android:layout_width="488dp"
+        android:layout_height="wrap_content"
+        android:focusable="true">
+    <ScrollView
+            android:id="@+id/keyboard_shortcuts_scroll_view"
+            android:layout_width="0dp"
+            android:layout_height="0dp"
+            android:layout_weight="1">
+        <LinearLayout
+                android:id="@+id/keyboard_shortcuts_container"
+                android:layout_width="match_parent"
+                android:layout_height="wrap_content"
+                android:orientation="vertical"/>
+    </ScrollView>
+    <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="?android:attr/listDivider"/>
+</LinearLayout>
diff --git a/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
new file mode 100644
index 0000000..802acfe
--- /dev/null
+++ b/packages/SystemUI/res/layout/keyboard_shortcuts_wrapper.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2016 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+              android:orientation="vertical"
+              android:layout_width="match_parent"
+              android:layout_height="wrap_content">
+</LinearLayout>
diff --git a/packages/SystemUI/res/values/colors.xml b/packages/SystemUI/res/values/colors.xml
index f0d9949..9bb6dc6 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -154,4 +154,9 @@
 
     <color name="switch_bar_background">#ff37474f</color>
     <color name="switch_accent_color">#ff7fcac3</color>
+
+    <!-- Keyboard shortcuts colors -->
+    <color name="ksh_system_group_color">#ff00bcd4</color>
+    <color name="ksh_application_group_color">#fff44336</color>
+    <color name="ksh_dialog_background_color">#ffffffff</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 6df31ff..ebe0d97 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -103,7 +103,7 @@
 
     <!-- The default tiles to display in QuickSettings -->
     <string name="quick_settings_tiles_default" translatable="false">
-        wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast
+        wifi,bt,flashlight,dnd,cell,battery,rotation,airplane,location,cast,work
     </string>
 
     <!-- The tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 240d32e..4edb976 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1175,7 +1175,7 @@
     }
 
     protected void toggleKeyboardShortcuts() {
-        getKeyboardShortcuts().toggleKeyboardShortcuts(mContext);
+        getKeyboardShortcuts().toggleKeyboardShortcuts();
     }
 
     protected void cancelPreloadingRecents() {
@@ -1518,7 +1518,7 @@
 
     protected KeyboardShortcuts getKeyboardShortcuts() {
         if (mKeyboardShortcuts == null) {
-            mKeyboardShortcuts = new KeyboardShortcuts();
+            mKeyboardShortcuts = new KeyboardShortcuts(mContext);
         }
 
         return mKeyboardShortcuts;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index b36fb7e..25e9a7a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -19,25 +19,38 @@
 import android.app.AlertDialog;
 import android.app.Dialog;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.graphics.Color;
+import android.graphics.Typeface;
 import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
+import android.os.Looper;
+import android.util.DisplayMetrics;
 import android.util.Log;
+import android.util.TypedValue;
 import android.view.KeyEvent;
 import android.view.KeyboardShortcutGroup;
 import android.view.KeyboardShortcutInfo;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.ViewGroup;
+import android.view.ViewGroup.LayoutParams;
 import android.view.Window;
-import android.view.WindowManager;
 import android.view.WindowManager.KeyboardShortcutsReceiver;
+import android.widget.LinearLayout;
+import android.widget.ScrollView;
+import android.widget.TextView;
 
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 
+import java.util.ArrayList;
 import java.util.List;
 
 import static android.content.Context.LAYOUT_INFLATER_SERVICE;
-import static android.graphics.Color.TRANSPARENT;
+import static android.graphics.Color.WHITE;
 import static android.view.Gravity.TOP;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
 
@@ -45,33 +58,44 @@
  * Contains functionality for handling keyboard shortcuts.
  */
 public class KeyboardShortcuts {
-    private static final String TAG = "KeyboardShortcuts";
+    private static final char SYSTEM_HOME_BASE_CHARACTER = '\u2386';
+    private static final char SYSTEM_BACK_BASE_CHARACTER = '\u007F';
+    private static final char SYSTEM_RECENTS_BASE_CHARACTER = '\u0009';
+
+    private final Handler mHandler = new Handler(Looper.getMainLooper());
+    private final Context mContext;
+    private final OnClickListener dialogCloseListener =  new DialogInterface.OnClickListener() {
+        public void onClick(DialogInterface dialog, int id) {
+            dismissKeyboardShortcutsDialog();
+        }
+    };
 
     private Dialog mKeyboardShortcutsDialog;
 
-    public KeyboardShortcuts() {}
+    public KeyboardShortcuts(Context context) {
+        this.mContext = context;
+    }
 
-    public void toggleKeyboardShortcuts(final Context context) {
+    public void toggleKeyboardShortcuts() {
         if (mKeyboardShortcutsDialog == null) {
-            Recents.getSystemServices().requestKeyboardShortcuts(context,
+            Recents.getSystemServices().requestKeyboardShortcuts(mContext,
                 new KeyboardShortcutsReceiver() {
                     @Override
                     public void onKeyboardShortcutsReceived(
                             final List<KeyboardShortcutGroup> result) {
                         KeyboardShortcutGroup systemGroup = new KeyboardShortcutGroup(
-                            context.getString(R.string.keyboard_shortcut_group_system));
+                            mContext.getString(R.string.keyboard_shortcut_group_system), true);
                         systemGroup.addItem(new KeyboardShortcutInfo(
-                            context.getString(R.string.keyboard_shortcut_group_system_home),
-                            '\u2386', KeyEvent.META_META_ON));
+                            mContext.getString(R.string.keyboard_shortcut_group_system_home),
+                            SYSTEM_HOME_BASE_CHARACTER, KeyEvent.META_META_ON));
                         systemGroup.addItem(new KeyboardShortcutInfo(
-                            context.getString(R.string.keyboard_shortcut_group_system_back),
-                            '\u007F', KeyEvent.META_META_ON));
+                            mContext.getString(R.string.keyboard_shortcut_group_system_back),
+                            SYSTEM_BACK_BASE_CHARACTER, KeyEvent.META_META_ON));
                         systemGroup.addItem(new KeyboardShortcutInfo(
-                            context.getString(R.string.keyboard_shortcut_group_system_recents),
-                            '\u0009', KeyEvent.META_ALT_ON));
+                            mContext.getString(R.string.keyboard_shortcut_group_system_recents),
+                            SYSTEM_RECENTS_BASE_CHARACTER, KeyEvent.META_ALT_ON));
                         result.add(systemGroup);
-                        Log.i(TAG, "Keyboard shortcuts received: " + String.valueOf(result));
-                        showKeyboardShortcutsDialog(context);
+                        showKeyboardShortcutsDialog(result);
                     }
                 });
         } else {
@@ -79,33 +103,6 @@
         }
     }
 
-    private void showKeyboardShortcutsDialog(Context context) {
-        // Create dialog.
-        AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(context);
-        LayoutInflater inflater = (LayoutInflater) context.getSystemService(
-                LAYOUT_INFLATER_SERVICE);
-        final View keyboardShortcutsView = inflater.inflate(
-                R.layout.keyboard_shortcuts_view, null);
-
-        populateKeyboardShortcuts(keyboardShortcutsView.findViewById(
-                R.id.keyboard_shortcuts_wrapper));
-        dialogBuilder.setView(keyboardShortcutsView);
-        mKeyboardShortcutsDialog = dialogBuilder.create();
-        mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
-
-        // Setup window.
-        Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
-        keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
-        keyboardShortcutsWindow.setBackgroundDrawable(
-                new ColorDrawable(TRANSPARENT));
-        keyboardShortcutsWindow.setGravity(TOP);
-        keyboardShortcutsView.post(new Runnable() {
-            public void run() {
-                mKeyboardShortcutsDialog.show();
-            }
-        });
-    }
-
     public void dismissKeyboardShortcutsDialog() {
         if (mKeyboardShortcutsDialog != null) {
             mKeyboardShortcutsDialog.dismiss();
@@ -113,11 +110,99 @@
         }
     }
 
-    /**
-     * @return {@code true} if the keyboard shortcuts have been successfully populated.
-     */
-    private boolean populateKeyboardShortcuts(View keyboardShortcutsLayout) {
-        // TODO: Populate shortcuts.
-        return true;
+    private void showKeyboardShortcutsDialog(
+            final List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+        // Need to post on the main thread.
+        mHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                // TODO: break all this code out into a handleShowKeyboard...
+                // Might add more things posted; should consider adding a custom handler so
+                // you can send the keyboardShortcutsGroups as part of the message.
+                AlertDialog.Builder dialogBuilder = new AlertDialog.Builder(mContext);
+                LayoutInflater inflater = (LayoutInflater) mContext.getSystemService(
+                        LAYOUT_INFLATER_SERVICE);
+                final View keyboardShortcutsView = inflater.inflate(
+                        R.layout.keyboard_shortcuts_view, null);
+                DisplayMetrics dm = mContext.getResources().getDisplayMetrics();
+                ScrollView scrollView = (ScrollView) keyboardShortcutsView.findViewById(
+                        R.id.keyboard_shortcuts_scroll_view);
+                // TODO: find a better way to set the height.
+                scrollView.setLayoutParams(new LinearLayout.LayoutParams(
+                        LayoutParams.WRAP_CONTENT,
+                        (int) (dm.heightPixels * dm.density)));
+
+                populateKeyboardShortcuts((LinearLayout) keyboardShortcutsView.findViewById(
+                        R.id.keyboard_shortcuts_container), keyboardShortcutGroups);
+                dialogBuilder.setView(keyboardShortcutsView);
+                dialogBuilder.setPositiveButton(R.string.quick_settings_done, dialogCloseListener);
+                mKeyboardShortcutsDialog = dialogBuilder.create();
+                mKeyboardShortcutsDialog.setCanceledOnTouchOutside(true);
+
+                // Setup window.
+                Window keyboardShortcutsWindow = mKeyboardShortcutsDialog.getWindow();
+                keyboardShortcutsWindow.setType(TYPE_SYSTEM_DIALOG);
+                keyboardShortcutsWindow.setBackgroundDrawable(
+                        mContext.getDrawable(R.color.ksh_dialog_background_color));
+                keyboardShortcutsWindow.setGravity(TOP);
+                mKeyboardShortcutsDialog.show();
+            }
+        });
+    }
+
+    private void populateKeyboardShortcuts(LinearLayout keyboardShortcutsLayout,
+            List<KeyboardShortcutGroup> keyboardShortcutGroups) {
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        final int keyboardShortcutGroupsSize = keyboardShortcutGroups.size();
+        for (int i = 0; i < keyboardShortcutGroupsSize; i++) {
+            KeyboardShortcutGroup group = keyboardShortcutGroups.get(i);
+            TextView categoryTitle = (TextView) inflater.inflate(
+                    R.layout.keyboard_shortcuts_category_title, keyboardShortcutsLayout, false);
+            categoryTitle.setText(group.getLabel());
+            categoryTitle.setTextColor(group.isSystemGroup()
+                    ? mContext.getColor(R.color.ksh_system_group_color)
+                    : mContext.getColor(R.color.ksh_application_group_color));
+            keyboardShortcutsLayout.addView(categoryTitle);
+
+            LinearLayout shortcutWrapper = (LinearLayout) inflater.inflate(
+                    R.layout.keyboard_shortcuts_wrapper, null);
+            final int itemsSize = group.getItems().size();
+            for (int j = 0; j < itemsSize; j++) {
+                KeyboardShortcutInfo info = group.getItems().get(j);
+                View shortcutView = inflater.inflate(R.layout.keyboard_shortcut_app_item, null);
+                TextView textView = (TextView) shortcutView
+                        .findViewById(R.id.keyboard_shortcuts_keyword);
+                textView.setText(info.getLabel());
+
+                List<String> shortcutKeys = getHumanReadableShortcutKeys(info);
+                final int shortcutKeysSize = shortcutKeys.size();
+                for (int k = 0; k < shortcutKeysSize; k++) {
+                    String shortcutKey = shortcutKeys.get(k);
+                    TextView shortcutKeyView = (TextView) inflater.inflate(
+                            R.layout.keyboard_shortcuts_key_view, null);
+                    shortcutKeyView.setText(shortcutKey);
+                    LinearLayout shortcutItemsContainer = (LinearLayout) shortcutView
+                            .findViewById(R.id.keyboard_shortcuts_item_container);
+                    shortcutItemsContainer.addView(shortcutKeyView);
+                }
+                shortcutWrapper.addView(shortcutView);
+            }
+
+            // TODO: merge container and wrapper into one xml file - wrapper is always a child of
+            // container.
+            LinearLayout shortcutsContainer = (LinearLayout) inflater.inflate(
+                    R.layout.keyboard_shortcuts_container, null);
+            shortcutsContainer.addView(shortcutWrapper);
+            keyboardShortcutsLayout.addView(shortcutsContainer);
+        }
+    }
+
+    private List<String> getHumanReadableShortcutKeys(KeyboardShortcutInfo info) {
+        // TODO: fix the shortcuts. Find or build an util which can produce human readable
+        // names of the baseCharacter and the modifiers.
+        List<String> shortcutKeys = new ArrayList<>();
+        shortcutKeys.add(KeyEvent.metaStateToString(info.getModifiers()).toUpperCase());
+        shortcutKeys.add(Character.getName(info.getBaseCharacter()).toUpperCase());
+        return shortcutKeys;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 3da8098..00b9888 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -19,7 +19,6 @@
 import android.app.Notification;
 import android.app.RemoteInput;
 import android.content.Context;
-import android.graphics.Outline;
 import android.graphics.Rect;
 import android.os.Build;
 import android.service.notification.StatusBarNotification;
@@ -27,7 +26,6 @@
 import android.view.NotificationHeaderView;
 import android.view.View;
 import android.view.ViewGroup;
-import android.view.ViewOutlineProvider;
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout;
 
@@ -53,6 +51,7 @@
 
     private final Rect mClipBounds = new Rect();
     private final int mMinContractedHeight;
+    private final int mNotificationContentMarginEnd;
     private final OnLayoutChangeListener mLayoutUpdater = new OnLayoutChangeListener() {
         @Override
         public void onLayoutChange(View v, int left, int top, int right, int bottom,
@@ -109,6 +108,8 @@
         mHybridViewManager = new HybridNotificationViewManager(getContext(), this);
         mMinContractedHeight = getResources().getDimensionPixelSize(
                 R.dimen.min_notification_layout_height);
+        mNotificationContentMarginEnd = getResources().getDimensionPixelSize(
+                com.android.internal.R.dimen.notification_content_margin_end);
         reset(true);
     }
 
@@ -128,6 +129,19 @@
             maxSize = MeasureSpec.getSize(heightMeasureSpec);
         }
         int maxChildHeight = 0;
+        if (mExpandedChild != null) {
+            int size = Math.min(maxSize, mNotificationMaxHeight);
+            ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
+            if (layoutParams.height >= 0) {
+                // An actual height is set
+                size = Math.min(maxSize, layoutParams.height);
+            }
+            int spec = size == Integer.MAX_VALUE
+                    ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
+                    : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
+            mExpandedChild.measure(widthMeasureSpec, spec);
+            maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
+        }
         if (mContractedChild != null) {
             int heightSpec;
             if (shouldContractedBeFixedSize()) {
@@ -143,19 +157,9 @@
                 mContractedChild.measure(widthMeasureSpec, heightSpec);
             }
             maxChildHeight = Math.max(maxChildHeight, measuredHeight);
-        }
-        if (mExpandedChild != null) {
-            int size = Math.min(maxSize, mNotificationMaxHeight);
-            ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
-            if (layoutParams.height >= 0) {
-                // An actual height is set
-                size = Math.min(maxSize, layoutParams.height);
+            if (updateContractedHeaderWidth()) {
+                mContractedChild.measure(widthMeasureSpec, heightSpec);
             }
-            int spec = size == Integer.MAX_VALUE
-                    ? MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)
-                    : MeasureSpec.makeMeasureSpec(size, MeasureSpec.AT_MOST);
-            mExpandedChild.measure(widthMeasureSpec, spec);
-            maxChildHeight = Math.max(maxChildHeight, mExpandedChild.getMeasuredHeight());
         }
         if (mHeadsUpChild != null) {
             int size = Math.min(maxSize, mHeadsUpHeight);
@@ -178,6 +182,44 @@
         setMeasuredDimension(width, ownHeight);
     }
 
+    private boolean updateContractedHeaderWidth() {
+        // We need to update the expanded and the collapsed header to have exactly the same with to
+        // have the expand buttons laid out at the same location.
+        NotificationHeaderView contractedHeader = mContractedWrapper.getNotificationHeader();
+        if (contractedHeader != null) {
+            if (mExpandedChild != null
+                    && mExpandedWrapper.getNotificationHeader() != null) {
+                NotificationHeaderView expandedHeader = mExpandedWrapper.getNotificationHeader();
+                int expandedSize = expandedHeader.getMeasuredWidth()
+                        - expandedHeader.getPaddingEnd();
+                int collapsedSize = contractedHeader.getMeasuredWidth()
+                        - expandedHeader.getPaddingEnd();
+                if (expandedSize != collapsedSize) {
+                    int paddingEnd = contractedHeader.getMeasuredWidth() - expandedSize;
+                    contractedHeader.setPadding(
+                            isLayoutRtl() ? paddingEnd : contractedHeader.getPaddingLeft(),
+                            contractedHeader.getPaddingTop(),
+                            isLayoutRtl() ? contractedHeader.getPaddingLeft() : paddingEnd,
+                            contractedHeader.getPaddingBottom());
+                    contractedHeader.setShowWorkBadgeAtEnd(true);
+                    return true;
+                }
+            } else {
+                int paddingEnd = mNotificationContentMarginEnd;
+                if (contractedHeader.getPaddingEnd() != paddingEnd) {
+                    contractedHeader.setPadding(
+                            isLayoutRtl() ? paddingEnd : contractedHeader.getPaddingLeft(),
+                            contractedHeader.getPaddingTop(),
+                            isLayoutRtl() ? contractedHeader.getPaddingLeft() : paddingEnd,
+                            contractedHeader.getPaddingBottom());
+                    contractedHeader.setShowWorkBadgeAtEnd(false);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
     private boolean shouldContractedBeFixedSize() {
         return mBeforeN && mContractedWrapper instanceof NotificationCustomViewWrapper;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
index bf291d3..81483c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/HeaderTransformState.java
@@ -30,6 +30,8 @@
     private static Pools.SimplePool<HeaderTransformState> sInstancePool
             = new Pools.SimplePool<>(40);
     private View mExpandButton;
+    private View mWorkProfileIcon;
+    private TransformState mWorkProfileState;
 
     @Override
     public void initFrom(View view) {
@@ -37,13 +39,16 @@
         if (view instanceof NotificationHeaderView) {
             NotificationHeaderView header = (NotificationHeaderView) view;
             mExpandButton = header.getExpandButton();
+            mWorkProfileState = TransformState.obtain();
+            mWorkProfileIcon = header.getWorkProfileIcon();
+            mWorkProfileState.initFrom(mWorkProfileIcon);
         }
     }
 
     @Override
     public boolean transformViewTo(TransformState otherState, Runnable endRunnable) {
         // if the transforming notification has a header, we have ensured that it looks the same
-        // but the expand button, so lets fade just that one.
+        // but the expand button, so lets fade just that one and transform the work profile icon.
         if (!(mTransformedView instanceof NotificationHeaderView)) {
             return false;
         }
@@ -66,7 +71,7 @@
     @Override
     public void transformViewFrom(TransformState otherState) {
         // if the transforming notification has a header, we have ensured that it looks the same
-        // but the expand button, so lets fade just that one.
+        // but the expand button, so lets fade just that one and transform the work profile icon.
         if (!(mTransformedView instanceof NotificationHeaderView)) {
             return;
         }
@@ -79,10 +84,14 @@
             if (headerChild.getVisibility() == View.GONE) {
                 continue;
             }
-            if (headerChild != mExpandButton) {
-                headerChild.setVisibility(View.VISIBLE);
-            } else {
+            if (headerChild == mExpandButton) {
                 CrossFadeHelper.fadeIn(mExpandButton);
+            } else {
+                headerChild.setVisibility(View.VISIBLE);
+                if (headerChild == mWorkProfileIcon) {
+                    mWorkProfileState.animateViewFrom(
+                            ((HeaderTransformState) otherState).mWorkProfileState);
+                }
             }
         }
         return;
@@ -99,6 +108,9 @@
     @Override
     public void recycle() {
         super.recycle();
+        if (mWorkProfileState != null) {
+            mWorkProfileState.recycle();
+        }
         sInstancePool.release(this);
     }
 
@@ -106,6 +118,7 @@
     protected void reset() {
         super.reset();
         mExpandButton = null;
+        mWorkProfileState = null;
     }
 
     public void setVisible(boolean visible) {
@@ -125,6 +138,10 @@
             if (headerChild == mExpandButton) {
                 headerChild.setAlpha(visible ? 1.0f : 0.0f);
             }
+            if (headerChild == mWorkProfileIcon) {
+                headerChild.setTranslationX(0);
+                headerChild.setTranslationY(0);
+            }
         }
     }
 
@@ -144,6 +161,10 @@
             headerChild.animate().cancel();
             headerChild.setVisibility(View.VISIBLE);
             headerChild.setAlpha(1.0f);
+            if (headerChild == mWorkProfileIcon) {
+                headerChild.setTranslationX(0);
+                headerChild.setTranslationY(0);
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 3e1c40a..870abb7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -286,6 +286,9 @@
     }
 
     public void setVisible(boolean visible) {
+        if (mTransformedView.getVisibility() == View.GONE) {
+            return;
+        }
         mTransformedView.animate().cancel();
         mTransformedView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
         mTransformedView.setAlpha(visible ? 1.0f : 0.0f);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 03809c0..53504cc 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -27,6 +27,7 @@
 import android.app.AlertDialog;
 import android.app.PendingIntent;
 import android.app.StatusBarManager;
+import android.app.UiAutomation;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
 import android.content.ContentResolver;
@@ -51,6 +52,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -258,10 +260,9 @@
                     UserState userState = getCurrentUserStateLocked();
                     // We have to reload the installed services since some services may
                     // have different attributes, resolve info (does not support equals),
-                    // etc. Remove them then to force reload. Do it even if automation is
-                    // running since when it goes away, we will have to reload as well.
+                    // etc. Remove them then to force reload.
                     userState.mInstalledServices.clear();
-                    if (userState.mUiAutomationService == null) {
+                    if (!userState.isUiAutomationSuppressingOtherServices()) {
                         if (readConfigurationForUserStateLocked(userState)) {
                             onUserStateChangedLocked(userState);
                         }
@@ -296,7 +297,7 @@
                                     TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
                                     userState.mTouchExplorationGrantedServices, userId);
                             // We will update when the automation service dies.
-                            if (userState.mUiAutomationService == null) {
+                            if (!userState.isUiAutomationSuppressingOtherServices()) {
                                 onUserStateChangedLocked(userState);
                             }
                             return;
@@ -330,7 +331,7 @@
                                         Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
                                         userState.mEnabledServices, userId);
                                 // We will update when the automation service dies.
-                                if (userState.mUiAutomationService == null) {
+                                if (!userState.isUiAutomationSuppressingOtherServices()) {
                                     onUserStateChangedLocked(userState);
                                 }
                             }
@@ -362,7 +363,7 @@
                 } else if (Intent.ACTION_USER_PRESENT.equals(action)) {
                     // We will update when the automation service dies.
                     UserState userState = getCurrentUserStateLocked();
-                    if (userState.mUiAutomationService == null) {
+                    if (!userState.isUiAutomationSuppressingOtherServices()) {
                         if (readConfigurationForUserStateLocked(userState)) {
                             onUserStateChangedLocked(userState);
                         }
@@ -473,11 +474,9 @@
             final int resolvedUserId = mSecurityPolicy
                     .resolveCallingUserIdEnforcingPermissionsLocked(userId);
 
-            // The automation service is a fake one and should not be reported
-            // to clients as being enabled. The automation service is always the
-            // only active one, if it exists.
+            // The automation service can suppress other services.
             UserState userState = getUserStateLocked(resolvedUserId);
-            if (userState.mUiAutomationService != null) {
+            if (userState.isUiAutomationSuppressingOtherServices()) {
                 return Collections.emptyList();
             }
 
@@ -490,7 +489,9 @@
                 final int serviceCount = services.size();
                 for (int i = 0; i < serviceCount; i++) {
                     Service service = services.get(i);
-                    if ((service.mFeedbackType & feedbackTypeBit) != 0) {
+                    // Don't report the UIAutomation (fake service)
+                    if (!sFakeAccessibilityServiceComponentName.equals(service.mComponentName)
+                            && (service.mFeedbackType & feedbackTypeBit) != 0) {
                         result.add(service.mAccessibilityServiceInfo);
                     }
                 }
@@ -621,7 +622,8 @@
     @Override
     public void registerUiTestAutomationService(IBinder owner,
             IAccessibilityServiceClient serviceClient,
-            AccessibilityServiceInfo accessibilityServiceInfo) {
+            AccessibilityServiceInfo accessibilityServiceInfo,
+            int flags) {
         mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
                 FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
 
@@ -645,15 +647,17 @@
 
             userState.mUiAutomationServiceOwner = owner;
             userState.mUiAutomationServiceClient = serviceClient;
-
-            // Set the temporary state.
+            userState.mUiAutomationFlags = flags;
             userState.mIsAccessibilityEnabled = true;
-            userState.mIsTouchExplorationEnabled = false;
-            userState.mIsEnhancedWebAccessibilityEnabled = false;
-            userState.mIsDisplayMagnificationEnabled = false;
-            userState.mIsAutoclickEnabled = false;
             userState.mInstalledServices.add(accessibilityServiceInfo);
-            userState.mEnabledServices.clear();
+            if (userState.isUiAutomationSuppressingOtherServices()) {
+                // Set the temporary state.
+                userState.mIsTouchExplorationEnabled = false;
+                userState.mIsEnhancedWebAccessibilityEnabled = false;
+                userState.mIsDisplayMagnificationEnabled = false;
+                userState.mIsAutoclickEnabled = false;
+                userState.mEnabledServices.clear();
+            }
             userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
             userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
 
@@ -694,7 +698,7 @@
             UserState userState = getCurrentUserStateLocked();
 
             // This is a nop if UI automation is enabled.
-            if (userState.mUiAutomationService != null) {
+            if (userState.isUiAutomationSuppressingOtherServices()) {
                 return;
             }
 
@@ -954,7 +958,15 @@
         final UserState state = getCurrentUserStateLocked();
         for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
             final Service service = state.mBoundServices.get(i);
-            service.notifyMagnificationChanged(region, scale, centerX, centerY);
+            service.notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+        }
+    }
+
+    private void notifySoftKeyboardShowModeChangedLocked(int showMode) {
+        final UserState state = getCurrentUserStateLocked();
+        for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+            final Service service = state.mBoundServices.get(i);
+            service.notifySoftKeyboardShowModeChangedLocked(showMode);
         }
     }
 
@@ -1027,6 +1039,9 @@
         if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
             userState.mEnabledServices.clear();
             userState.mEnabledServices.addAll(mTempComponentNameSet);
+            if (userState.mUiAutomationService != null) {
+                userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
+            }
             mTempComponentNameSet.clear();
             return true;
         }
@@ -1400,6 +1415,7 @@
         updateEnhancedWebAccessibilityLocked(userState);
         updateDisplayColorAdjustmentSettingsLocked(userState);
         updateMagnificationLocked(userState);
+        updateSoftKeyboardShowModeLocked(userState);
         scheduleUpdateInputFilter(userState);
         scheduleUpdateClientsIfNeededLocked(userState);
     }
@@ -1616,6 +1632,18 @@
         return false;
     }
 
+    private boolean readSoftKeyboardShowModeChangedLocked(UserState userState) {
+        final int softKeyboardShowMode = Settings.Secure.getIntForUser(
+                mContext.getContentResolver(),
+                Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, 0,
+                userState.mUserId);
+        if (softKeyboardShowMode != userState.mSoftKeyboardShowMode) {
+            userState.mSoftKeyboardShowMode = softKeyboardShowMode;
+            return true;
+        }
+        return false;
+    }
+
     private void updateTouchExplorationLocked(UserState userState) {
         boolean enabled = false;
         final int serviceCount = userState.mBoundServices.size();
@@ -1750,6 +1778,25 @@
         return false;
     }
 
+    private void updateSoftKeyboardShowModeLocked(UserState userState) {
+        final int userId = userState.mUserId;
+        if (userId == mCurrentUserId) {
+            // Check whether any Accessibility Services are still enabled and, if not, remove flag
+            // requesting no soft keyboard
+            final boolean accessibilityRequestingNoIme = userState.mSoftKeyboardShowMode == 1;
+            if (accessibilityRequestingNoIme && !userState.mIsAccessibilityEnabled) {
+                // No active Accessibility Services can be requesting the soft keyboard to be hidden
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+                        0,
+                        userState.mUserId);
+                userState.mSoftKeyboardShowMode = 0;
+            }
+
+            notifySoftKeyboardShowModeChangedLocked(userState.mSoftKeyboardShowMode);
+        }
+    }
+
     private MagnificationSpec getCompatibleMagnificationSpecLocked(int windowId) {
         IBinder windowToken = mGlobalWindowTokens.get(windowId);
         if (windowToken == null) {
@@ -2095,7 +2142,7 @@
         };
 
         // Handler for scheduling method invocations on the main thread.
-        public InvocationHandler mInvocationHandler = new InvocationHandler(
+        public final InvocationHandler mInvocationHandler = new InvocationHandler(
                 mMainHandler.getLooper());
 
         public Service(int userId, ComponentName componentName,
@@ -2290,17 +2337,20 @@
             }
         }
 
+        private boolean isCalledForCurrentUserLocked() {
+            // We treat calls from a profile as if made by its parent as profiles
+            // share the accessibility state of the parent. The call below
+            // performs the current profile parent resolution.
+            final int resolvedUserId = mSecurityPolicy
+                    .resolveCallingUserIdEnforcingPermissionsLocked(UserHandle.USER_CURRENT);
+            return resolvedUserId == mCurrentUserId;
+        }
+
         @Override
         public List<AccessibilityWindowInfo> getWindows() {
             ensureWindowsAvailableTimed();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its perent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return null;
                 }
                 final boolean permissionGranted =
@@ -2328,13 +2378,7 @@
         public AccessibilityWindowInfo getWindow(int windowId) {
             ensureWindowsAvailableTimed();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return null;
                 }
                 final boolean permissionGranted =
@@ -2361,13 +2405,7 @@
             IAccessibilityInteractionConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2418,13 +2456,7 @@
             IAccessibilityInteractionConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2475,13 +2507,7 @@
             IAccessibilityInteractionConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2532,13 +2558,7 @@
             IAccessibilityInteractionConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdForFindFocusLocked(
@@ -2590,13 +2610,7 @@
             IAccessibilityInteractionConnection connection = null;
             Region partialInteractiveRegion = Region.obtain();
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2663,13 +2677,7 @@
             final int resolvedWindowId;
             IAccessibilityInteractionConnection connection = null;
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 resolvedWindowId = resolveAccessibilityWindowIdLocked(accessibilityWindowId);
@@ -2702,13 +2710,7 @@
         @Override
         public boolean performGlobalAction(int action) {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
             }
@@ -2743,13 +2745,7 @@
         @Override
         public float getMagnificationScale() {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return 1.0f;
                 }
             }
@@ -2764,13 +2760,7 @@
         @Override
         public Region getMagnifiedRegion() {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return Region.obtain();
                 }
             }
@@ -2787,13 +2777,7 @@
         @Override
         public float getMagnificationCenterX() {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return 0.0f;
                 }
             }
@@ -2808,13 +2792,7 @@
         @Override
         public float getMagnificationCenterY() {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return 0.0f;
                 }
             }
@@ -2829,13 +2807,7 @@
         @Override
         public boolean resetMagnification(boolean animate) {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2855,13 +2827,7 @@
         public boolean setMagnificationScaleAndCenter(float scale, float centerX, float centerY,
                 boolean animate) {
             synchronized (mLock) {
-                // We treat calls from a profile as if made by its parent as profiles
-                // share the accessibility state of the parent. The call below
-                // performs the current profile parent resolution.
-                final int resolvedUserId = mSecurityPolicy
-                        .resolveCallingUserIdEnforcingPermissionsLocked(
-                                UserHandle.USER_CURRENT);
-                if (resolvedUserId != mCurrentUserId) {
+                if (!isCalledForCurrentUserLocked()) {
                     return false;
                 }
                 final boolean permissionGranted = mSecurityPolicy.canControlMagnification(this);
@@ -2884,6 +2850,33 @@
         }
 
         @Override
+        public boolean setSoftKeyboardShowMode(int showMode) {
+            final UserState userState;
+            synchronized (mLock) {
+                if (!isCalledForCurrentUserLocked()) {
+                    return false;
+                }
+
+                userState = getCurrentUserStateLocked();
+            }
+
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                Settings.Secure.putIntForUser(mContext.getContentResolver(),
+                        Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE, showMode,
+                        userState.mUserId);
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+            return true;
+        }
+
+        @Override
+        public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+            mInvocationHandler.setSoftKeyboardCallbackEnabled(enabled);
+        }
+
+        @Override
         public void dump(FileDescriptor fd, final PrintWriter pw, String[] args) {
             mSecurityPolicy.enforceCallingPermission(Manifest.permission.DUMP, FUNCTION_DUMP);
             synchronized (mLock) {
@@ -3073,9 +3066,14 @@
                     InvocationHandler.MSG_CLEAR_ACCESSIBILITY_CACHE);
         }
 
-        public void notifyMagnificationChanged(@NonNull Region region,
+        public void notifyMagnificationChangedLocked(@NonNull Region region,
                 float scale, float centerX, float centerY) {
-            mInvocationHandler.notifyMagnificationChanged(region, scale, centerX, centerY);
+            mInvocationHandler
+                    .notifyMagnificationChangedLocked(region, scale, centerX, centerY);
+        }
+
+        public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+            mInvocationHandler.notifySoftKeyboardShowModeChangedLocked(showState);
         }
 
         /**
@@ -3097,6 +3095,25 @@
             }
         }
 
+        /**
+         * Called by the invocation handler to notify the service that the state of the soft
+         * keyboard show mode has changed.
+         */
+        private void notifySoftKeyboardShowModeChangedInternal(int showState) {
+            final IAccessibilityServiceClient listener;
+            synchronized (mLock) {
+                listener = mServiceInterface;
+            }
+            if (listener != null) {
+                try {
+                    listener.onSoftKeyboardShowModeChanged(showState);
+                } catch (RemoteException re) {
+                    Slog.e(LOG_TAG, "Error sending soft keyboard show mode changes to " + mService,
+                            re);
+                }
+            }
+        }
+
         private void notifyGestureInternal(int gestureId) {
             final IAccessibilityServiceClient listener;
             synchronized (mLock) {
@@ -3232,8 +3249,10 @@
             public static final int MSG_CLEAR_ACCESSIBILITY_CACHE = 2;
 
             private static final int MSG_ON_MAGNIFICATION_CHANGED = 5;
+            private static final int MSG_ON_SOFT_KEYBOARD_STATE_CHANGED = 6;
 
             private boolean mIsMagnificationCallbackEnabled = false;
+            private boolean mIsSoftKeyboardCallbackEnabled = false;
 
             public InvocationHandler(Looper looper) {
                 super(looper, null, true);
@@ -3261,13 +3280,18 @@
                         notifyMagnificationChangedInternal(region, scale, centerX, centerY);
                     } break;
 
+                    case MSG_ON_SOFT_KEYBOARD_STATE_CHANGED: {
+                        final int showState = (int) message.arg1;
+                        notifySoftKeyboardShowModeChangedInternal(showState);
+                    } break;
+
                     default: {
                         throw new IllegalArgumentException("Unknown message: " + type);
                     }
                 }
             }
 
-            public void notifyMagnificationChanged(@NonNull Region region, float scale,
+            public void notifyMagnificationChangedLocked(@NonNull Region region, float scale,
                     float centerX, float centerY) {
                 if (!mIsMagnificationCallbackEnabled) {
                     // Callback is disabled, don't bother packing args.
@@ -3287,8 +3311,20 @@
             public void setMagnificationCallbackEnabled(boolean enabled) {
                 mIsMagnificationCallbackEnabled = enabled;
             }
-        }
 
+            public void notifySoftKeyboardShowModeChangedLocked(int showState) {
+                if (!mIsSoftKeyboardCallbackEnabled) {
+                    return;
+                }
+
+                final Message msg = obtainMessage(MSG_ON_SOFT_KEYBOARD_STATE_CHANGED, showState, 0);
+                msg.sendToTarget();
+            }
+
+            public void setSoftKeyboardCallbackEnabled(boolean enabled) {
+                mIsSoftKeyboardCallbackEnabled = enabled;
+            }
+        }
     }
 
     final class WindowsForAccessibilityCallback implements
@@ -3969,6 +4005,8 @@
 
         public int mLastSentClientState = -1;
 
+        public int mSoftKeyboardShowMode = 0;
+
         public boolean mIsAccessibilityEnabled;
         public boolean mIsTouchExplorationEnabled;
         public boolean mIsTextHighContrastEnabled;
@@ -3981,6 +4019,7 @@
         public boolean mAccessibilityFocusOnlyInActiveWindow;
 
         private Service mUiAutomationService;
+        private int mUiAutomationFlags;
         private IAccessibilityServiceClient mUiAutomationServiceClient;
 
         private IBinder mUiAutomationServiceOwner;
@@ -4040,10 +4079,12 @@
             mIsEnhancedWebAccessibilityEnabled = false;
             mIsDisplayMagnificationEnabled = false;
             mIsAutoclickEnabled = false;
+            mSoftKeyboardShowMode = 0;
         }
 
         public void destroyUiAutomationService() {
             mUiAutomationService = null;
+            mUiAutomationFlags = 0;
             mUiAutomationServiceClient = null;
             if (mUiAutomationServiceOwner != null) {
                 mUiAutomationServiceOwner.unlinkToDeath(
@@ -4051,6 +4092,11 @@
                 mUiAutomationServiceOwner = null;
             }
         }
+
+        boolean isUiAutomationSuppressingOtherServices() {
+            return ((mUiAutomationService != null) && (mUiAutomationFlags
+                    & UiAutomation.FLAG_DONT_SUPPRESS_ACCESSIBILITY_SERVICES) == 0);
+        }
     }
 
     private final class AccessibilityContentObserver extends ContentObserver {
@@ -4091,6 +4137,9 @@
         private final Uri mHighTextContrastUri = Settings.Secure.getUriFor(
                 Settings.Secure.ACCESSIBILITY_HIGH_TEXT_CONTRAST_ENABLED);
 
+        private final Uri mAccessibilitySoftKeyboardModeUri = Settings.Secure.getUriFor(
+                Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
+
         public AccessibilityContentObserver(Handler handler) {
             super(handler);
         }
@@ -4121,6 +4170,8 @@
                     mDisplayColorMatrixUri, false, this, UserHandle.USER_ALL);
             contentResolver.registerContentObserver(
                     mHighTextContrastUri, false, this, UserHandle.USER_ALL);
+            contentResolver.registerContentObserver(
+                    mAccessibilitySoftKeyboardModeUri, false, this, UserHandle.USER_ALL);
         }
 
         @Override
@@ -4130,8 +4181,8 @@
                 // we are checking for changes only the parent settings.
                 UserState userState = getCurrentUserStateLocked();
 
-                // We will update when the automation service dies.
-                if (userState.mUiAutomationService != null) {
+                // If the automation service is suppressing, we will update when it dies.
+                if (userState.isUiAutomationSuppressingOtherServices()) {
                     return;
                 }
 
@@ -4175,6 +4226,10 @@
                     if (readHighTextContrastEnabledSettingLocked(userState)) {
                         onUserStateChangedLocked(userState);
                     }
+                } else if (mAccessibilitySoftKeyboardModeUri.equals(uri)) {
+                    if (readSoftKeyboardShowModeChangedLocked(userState)) {
+                        onUserStateChangedLocked(userState);
+                    }
                 }
             }
         }
diff --git a/services/core/java/com/android/server/InputMethodManagerService.java b/services/core/java/com/android/server/InputMethodManagerService.java
index 4a123df..d77def6 100644
--- a/services/core/java/com/android/server/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/InputMethodManagerService.java
@@ -448,6 +448,7 @@
     private int[] mSubtypeIds;
     private Locale mLastSystemLocale;
     private boolean mShowImeWithHardKeyboard;
+    private boolean mAccessibilityRequestingNoSoftKeyboard;
     private final MyPackageMonitor mMyPackageMonitor = new MyPackageMonitor();
     private final IPackageManager mIPackageManager;
     private final String mSlotIme;
@@ -485,15 +486,31 @@
                     Settings.Secure.SELECTED_INPUT_METHOD_SUBTYPE), false, this, userId);
             resolver.registerContentObserver(Settings.Secure.getUriFor(
                     Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD), false, this, userId);
+            resolver.registerContentObserver(Settings.Secure.getUriFor(
+                    Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE), false, this, userId);
             mRegistered = true;
         }
 
         @Override public void onChange(boolean selfChange, Uri uri) {
-            final Uri showImeUri =
-                    Settings.Secure.getUriFor(Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+            final Uri showImeUri = Settings.Secure.getUriFor(
+                    Settings.Secure.SHOW_IME_WITH_HARD_KEYBOARD);
+            final Uri accessibilityRequestingNoImeUri = Settings.Secure.getUriFor(
+                    Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE);
             synchronized (mMethodMap) {
                 if (showImeUri.equals(uri)) {
                     updateKeyboardFromSettingsLocked();
+                } else if (accessibilityRequestingNoImeUri.equals(uri)) {
+                    mAccessibilityRequestingNoSoftKeyboard = Settings.Secure.getIntForUser(
+                            mContext.getContentResolver(),
+                            Settings.Secure.ACCESSIBILITY_SOFT_KEYBOARD_MODE,
+                            0, mUserId) == 1;
+                    if (mAccessibilityRequestingNoSoftKeyboard) {
+                        final boolean showRequested = mShowRequested;
+                        hideCurrentInputLocked(0, null);
+                        mShowRequested = showRequested;
+                    } else if (mShowRequested) {
+                        showCurrentInputLocked(InputMethodManager.SHOW_IMPLICIT, null);
+                    }
                 } else {
                     boolean enabledChanged = false;
                     String newEnabled = mSettings.getEnabledInputMethodsStr();
@@ -655,7 +672,7 @@
                 boolean changed = false;
 
                 if (curIm != null) {
-                    int change = isPackageDisappearing(curIm.getPackageName()); 
+                    int change = isPackageDisappearing(curIm.getPackageName());
                     if (change == PACKAGE_TEMPORARY_CHANGE
                             || change == PACKAGE_PERMANENT_CHANGE) {
                         ServiceInfo si = null;
@@ -2073,12 +2090,15 @@
 
     boolean showCurrentInputLocked(int flags, ResultReceiver resultReceiver) {
         mShowRequested = true;
-        if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
-            mShowExplicitlyRequested = true;
+        if (mAccessibilityRequestingNoSoftKeyboard) {
+            return false;
         }
+
         if ((flags&InputMethodManager.SHOW_FORCED) != 0) {
             mShowExplicitlyRequested = true;
             mShowForced = true;
+        } else if ((flags&InputMethodManager.SHOW_IMPLICIT) == 0) {
+            mShowExplicitlyRequested = true;
         }
 
         if (!mSystemReady) {
@@ -3265,7 +3285,7 @@
                         "Requires permission "
                         + android.Manifest.permission.WRITE_SECURE_SETTINGS);
             }
-            
+
             long ident = Binder.clearCallingIdentity();
             try {
                 return setInputMethodEnabledLocked(id, enabled);
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index e9f0a7a..d0cd536 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -200,7 +200,7 @@
                 PendingIntent.FLAG_UPDATE_CURRENT);
 
         Notification notification = new Notification.Builder(mContext)
-                .setSmallIcon(com.android.internal.R.drawable.stat_sys_warning)
+                .setSmallIcon(com.android.internal.R.drawable.ic_secure)
                 .setWhen(0)
                 .setOngoing(true)
                 .setTicker(title)
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index 573afd6..033a243 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -16,7 +16,9 @@
 
 package com.android.server.input;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.util.LocaleList;
 import android.view.Display;
 import com.android.internal.inputmethod.InputMethodSubtypeHandle;
 import com.android.internal.os.SomeArgs;
@@ -780,8 +782,10 @@
                         || layout.getProductId() != d.getProductId()) {
                     return;
                 }
-                for (Locale l : layout.getLocales()) {
-                    if (isCompatibleLocale(systemLocale, l)) {
+                final LocaleList locales = layout.getLocales();
+                final int numLocales = locales.size();
+                for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                    if (isCompatibleLocale(systemLocale, locales.get(localeIndex))) {
                         layouts.add(layout);
                         break;
                     }
@@ -799,9 +803,12 @@
         final int N = layouts.size();
         for (int i = 0; i < N; i++) {
             KeyboardLayout layout = layouts.get(i);
-            for (Locale l : layout.getLocales()) {
-                if (l.getCountry().equals(systemLocale.getCountry())
-                        && l.getVariant().equals(systemLocale.getVariant())) {
+            final LocaleList locales = layout.getLocales();
+            final int numLocales = locales.size();
+            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale.getCountry().equals(systemLocale.getCountry())
+                        && locale.getVariant().equals(systemLocale.getVariant())) {
                     return layout.getDescriptor();
                 }
             }
@@ -809,8 +816,11 @@
         // Then try an exact match of language and country
         for (int i = 0; i < N; i++) {
             KeyboardLayout layout = layouts.get(i);
-            for (Locale l : layout.getLocales()) {
-                if (l.getCountry().equals(systemLocale.getCountry())) {
+            final LocaleList locales = layout.getLocales();
+            final int numLocales = locales.size();
+            for (int localeIndex = 0; localeIndex < numLocales; ++localeIndex) {
+                final Locale locale = locales.get(localeIndex);
+                if (locale.getCountry().equals(systemLocale.getCountry())) {
                     return layout.getDescriptor();
                 }
             }
@@ -1170,7 +1180,7 @@
                                     0);
                             String languageTags = a.getString(
                                     com.android.internal.R.styleable.KeyboardLayout_locale);
-                            Locale[] locales = getLocalesFromLanguageTags(languageTags);
+                            LocaleList locales = getLocalesFromLanguageTags(languageTags);
                             int vid = a.getInt(
                                     com.android.internal.R.styleable.KeyboardLayout_vendorId, -1);
                             int pid = a.getInt(
@@ -1210,16 +1220,12 @@
         }
     }
 
-    private static Locale[] getLocalesFromLanguageTags(String languageTags) {
+    @NonNull
+    private static LocaleList getLocalesFromLanguageTags(String languageTags) {
         if (TextUtils.isEmpty(languageTags)) {
-            return new Locale[0];
+            return LocaleList.getEmptyLocaleList();
         }
-        String[] tags = languageTags.split("\\|");
-        Locale[] locales = new Locale[tags.length];
-        for (int i = 0; i < tags.length; i++) {
-            locales[i] = Locale.forLanguageTag(tags[i]);
-        }
-        return locales;
+        return LocaleList.forLanguageTags(languageTags.replace('|', ','));
     }
 
     /**
@@ -1596,7 +1602,7 @@
         final int accessibilityConfig = Settings.Secure.getIntForUser(
                 mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_LARGE_POINTER_ICON,
                 0, UserHandle.USER_CURRENT);
-        PointerIcon.sUseLargeIcons = (accessibilityConfig == 1);
+        PointerIcon.setUseLargeIcons(accessibilityConfig == 1);
         nativeReloadPointerIcons(mPtr);
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageDexOptimizer.java b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
index 4d66e10..bce7223 100644
--- a/services/core/java/com/android/server/pm/PackageDexOptimizer.java
+++ b/services/core/java/com/android/server/pm/PackageDexOptimizer.java
@@ -70,7 +70,8 @@
     }
 
     static boolean canOptimizePackage(PackageParser.Package pkg) {
-        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
+        return pkg.canHaveOatDir() &&
+                ((pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0);
     }
 
     /**
diff --git a/services/core/java/com/android/server/tv/TvInputManagerService.java b/services/core/java/com/android/server/tv/TvInputManagerService.java
index 62e7fb4..318f966 100644
--- a/services/core/java/com/android/server/tv/TvInputManagerService.java
+++ b/services/core/java/com/android/server/tv/TvInputManagerService.java
@@ -71,6 +71,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.util.SparseArray;
 import android.view.InputChannel;
@@ -779,15 +780,14 @@
         }
     }
 
-    private void notifyTvInputInfoChanged(UserState userState, String inputId,
-            TvInputInfo inputInfo) {
+    private void setTvInputInfoLocked(UserState userState, TvInputInfo inputInfo) {
         if (DEBUG) {
-            Slog.d(TAG, "notifyTvInputInfoChanged(inputId=" + inputId + ", inputInfo=" + inputInfo
-                    + ")");
+            Slog.d(TAG, "setTvInputInfoLocked(inputInfo=" + inputInfo + ")");
         }
+        // TODO: Also update the internal input list.
         for (ITvInputManagerCallback callback : userState.callbackSet) {
             try {
-                callback.onTvInputInfoChanged(inputId, inputInfo);
+                callback.onTvInputInfoChanged(inputInfo);
             } catch (RemoteException e) {
                 Slog.e(TAG, "failed to report changed input info to callback", e);
             }
@@ -846,6 +846,36 @@
             }
         }
 
+        public void setTvInputInfo(TvInputInfo inputInfo, int userId) {
+            String inputInfoPackageName = inputInfo.getServiceInfo().packageName;
+            String callingPackageName = getCallingPackageName();
+            if (!TextUtils.equals(inputInfoPackageName, callingPackageName)) {
+                throw new IllegalArgumentException("calling package " + callingPackageName
+                        + " is not allowed to change TvInputInfo for " + inputInfoPackageName);
+            }
+
+            final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
+                    Binder.getCallingUid(), userId, "setTvInputInfoChanged");
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mLock) {
+                    UserState userState = getOrCreateUserStateLocked(resolvedUserId);
+                    setTvInputInfoLocked(userState, inputInfo);
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
+
+        private String getCallingPackageName() {
+            final String[] packages = mContext.getPackageManager().getPackagesForUid(
+                    Binder.getCallingUid());
+            if (packages != null && packages.length > 0) {
+                return packages[0];
+            }
+            return "unknown";
+        }
+
         @Override
         public int getTvInputState(String inputId, int userId) {
             final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(),
@@ -2233,18 +2263,6 @@
                 }
             }
         }
-
-        @Override
-        public void setTvInputInfo(String inputId, TvInputInfo inputInfo) {
-            ensureValidInput(inputInfo);
-            synchronized (mLock) {
-                if (DEBUG) {
-                    Slog.d(TAG, "setTvInputInfo(" + inputInfo + ")");
-                }
-                UserState userState = getOrCreateUserStateLocked(mUserId);
-                notifyTvInputInfoChanged(userState, inputId, inputInfo);
-            }
-        }
     }
 
     private final class SessionCallback extends ITvInputSessionCallback.Stub {
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 39983dd..c7d7096 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -42,6 +42,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.BitmapRegionDecoder;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Binder;
@@ -71,6 +74,7 @@
 import android.view.IWindowManager;
 import android.view.WindowManager;
 
+import java.io.BufferedOutputStream;
 import java.io.FileDescriptor;
 import java.io.IOException;
 import java.io.InputStream;
@@ -96,7 +100,7 @@
 
 public class WallpaperManagerService extends IWallpaperManager.Stub {
     static final String TAG = "WallpaperManagerService";
-    static final boolean DEBUG = false;
+    static final boolean DEBUG = true;
 
     final Object mLock = new Object[0];
 
@@ -106,7 +110,8 @@
      */
     static final long MIN_WALLPAPER_CRASH_TIME = 10000;
     static final int MAX_WALLPAPER_COMPONENT_LOG_LENGTH = 128;
-    static final String WALLPAPER = "wallpaper";
+    static final String WALLPAPER = "wallpaper_orig";
+    static final String WALLPAPER_CROP = "wallpaper";
     static final String WALLPAPER_INFO = "wallpaper_info.xml";
 
     /**
@@ -120,6 +125,7 @@
         final WallpaperData mWallpaper;
         final File mWallpaperDir;
         final File mWallpaperFile;
+        final File mWallpaperCropFile;
         final File mWallpaperInfoFile;
 
         public WallpaperObserver(WallpaperData wallpaper) {
@@ -128,6 +134,7 @@
             mWallpaperDir = getWallpaperDir(wallpaper.userId);
             mWallpaper = wallpaper;
             mWallpaperFile = new File(mWallpaperDir, WALLPAPER);
+            mWallpaperCropFile = new File(mWallpaperDir, WALLPAPER_CROP);
             mWallpaperInfoFile = new File(mWallpaperDir, WALLPAPER_INFO);
         }
 
@@ -136,8 +143,10 @@
             if (path == null) {
                 return;
             }
+            final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+            final File changedFile = new File(mWallpaperDir, path);
+
             synchronized (mLock) {
-                File changedFile = new File(mWallpaperDir, path);
                 if (mWallpaperFile.equals(changedFile)
                         || mWallpaperInfoFile.equals(changedFile)) {
                     // changing the wallpaper means we'll need to back up the new one
@@ -148,22 +157,111 @@
                 }
                 if (mWallpaperFile.equals(changedFile)) {
                     notifyCallbacksLocked(mWallpaper);
-                    final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
                     if (mWallpaper.wallpaperComponent == null
                             || event != CLOSE_WRITE // includes the MOVED_TO case
                             || mWallpaper.imageWallpaperPending) {
                         if (written) {
+                            // The image source has finished writing the source image,
+                            // so we now produce the crop rect (in the background), and
+                            // only publish the new displayable (sub)image as a result
+                            // of that work.
+                            generateCrop(mWallpaper);
                             mWallpaper.imageWallpaperPending = false;
+                            if (mWallpaper.setComplete != null) {
+                                try {
+                                    mWallpaper.setComplete.onWallpaperChanged();
+                                } catch (RemoteException e) {
+                                    // if this fails we don't really care; the setting app may just
+                                    // have crashed and that sort of thing is a fact of life.
+                                }
+                            }
+                            bindWallpaperComponentLocked(mImageWallpaper, true,
+                                    false, mWallpaper, null);
+                            saveSettingsLocked(mWallpaper);
                         }
-                        bindWallpaperComponentLocked(mImageWallpaper, true,
-                                false, mWallpaper, null);
-                        saveSettingsLocked(mWallpaper);
                     }
                 }
             }
         }
     }
 
+    /**
+     * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
+     * for display.
+     */
+    private void generateCrop(WallpaperData wallpaper) {
+        boolean success = false;
+        boolean needCrop = false;
+
+        // Analyse the source; needed in multiple cases
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inJustDecodeBounds = true;
+        BitmapFactory.decodeFile(wallpaper.wallpaperFile.getAbsolutePath(), options);
+
+        // Legacy case uses an empty crop rect here, so we just preserve the
+        // source image verbatim
+        if (!wallpaper.cropHint.isEmpty()) {
+            // ...clamp the crop rect to the measured bounds...
+            wallpaper.cropHint.right = Math.min(wallpaper.cropHint.right, options.outWidth);
+            wallpaper.cropHint.bottom = Math.min(wallpaper.cropHint.bottom, options.outHeight);
+            // ...and don't bother cropping if what we're left with is identity
+            needCrop = (options.outHeight >= wallpaper.cropHint.height()
+                    && options.outWidth >= wallpaper.cropHint.width());
+        }
+
+        if (!needCrop) {
+            // Simple case:  the nominal crop is at least as big as the source image,
+            // so we take the whole thing and just copy the image file directly.
+            if (DEBUG) {
+                Slog.v(TAG, "Null crop of new wallpaper; copying");
+            }
+            success = FileUtils.copyFile(wallpaper.wallpaperFile, wallpaper.cropFile);
+            if (!success) {
+                wallpaper.cropFile.delete();
+                // TODO: fall back to default wallpaper in this case
+            }
+        } else {
+            // Fancy case: the crop is a subrect of the source
+            FileOutputStream f = null;
+            BufferedOutputStream bos = null;
+            try {
+                BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(
+                        wallpaper.wallpaperFile.getAbsolutePath(), false);
+                Bitmap cropped = decoder.decodeRegion(wallpaper.cropHint, null);
+                decoder.recycle();
+
+                if (cropped == null) {
+                    Slog.e(TAG, "Could not decode new wallpaper");
+                } else {
+                    f = new FileOutputStream(wallpaper.cropFile);
+                    bos = new BufferedOutputStream(f, 32*1024);
+                    cropped.compress(Bitmap.CompressFormat.PNG, 90, bos);
+                    bos.flush();  // don't rely on the implicit flush-at-close when noting success
+                    success = true;
+                }
+            } catch (IOException e) {
+                if (DEBUG) {
+                    Slog.e(TAG, "I/O error decoding crop: " + e.getMessage());
+                }
+            } finally {
+                IoUtils.closeQuietly(bos);
+                IoUtils.closeQuietly(f);
+            }
+        }
+
+        if (!success) {
+            Slog.e(TAG, "Unable to apply new wallpaper");
+            wallpaper.cropFile.delete();
+        }
+
+        if (wallpaper.cropFile.exists()) {
+            boolean didRestorecon = SELinux.restorecon(wallpaper.cropFile.getAbsoluteFile());
+            if (DEBUG) {
+                Slog.v(TAG, "restorecon() of crop file returned " + didRestorecon);
+            }
+        }
+    }
+
     final Context mContext;
     final IWindowManager mIWindowManager;
     final IPackageManager mIPackageManager;
@@ -191,7 +289,8 @@
 
         int userId;
 
-        File wallpaperFile;
+        final File wallpaperFile;
+        final File cropFile;
 
         /**
          * Client is currently writing a new image wallpaper.
@@ -199,6 +298,11 @@
         boolean imageWallpaperPending;
 
         /**
+         * Callback once the set + crop is finished
+         */
+        IWallpaperManagerCallback setComplete;
+
+        /**
          * Resource name if using a picture from the wallpaper gallery
          */
         String name = "";
@@ -232,11 +336,26 @@
         int width = -1;
         int height = -1;
 
+        /**
+         * The crop hint supplied for displaying a subset of the source image
+         */
+        final Rect cropHint = new Rect(0, 0, 0, 0);
+
         final Rect padding = new Rect(0, 0, 0, 0);
 
         WallpaperData(int userId) {
             this.userId = userId;
             wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
+            cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+        }
+
+        // Only called in single-threaded boot sequence mode
+        boolean ensureCropExists() {
+            // if the crop file is not present, copy over the source image to use verbatim
+            if (!cropFile.exists()) {
+                return FileUtils.copyFile(wallpaperFile, cropFile);
+            }
+            return true;
         }
     }
 
@@ -524,6 +643,9 @@
     public void systemRunning() {
         if (DEBUG) Slog.v(TAG, "systemReady");
         WallpaperData wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
+        if (!wallpaper.ensureCropExists()) {
+            clearWallpaperLocked(false, UserHandle.USER_SYSTEM, null);
+        }
         switchWallpaper(wallpaper, null);
         wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
         wallpaper.wallpaperObserver.startWatching();
@@ -602,6 +724,8 @@
             onStoppingUser(userId);
             File wallpaperFile = new File(getWallpaperDir(userId), WALLPAPER);
             wallpaperFile.delete();
+            File cropFile = new File(getWallpaperDir(userId), WALLPAPER_CROP);
+            cropFile.delete();
             File wallpaperInfoFile = new File(getWallpaperDir(userId), WALLPAPER_INFO);
             wallpaperInfoFile.delete();
         }
@@ -653,9 +777,9 @@
         if (wallpaper == null) {
             return;
         }
-        File f = new File(getWallpaperDir(userId), WALLPAPER);
-        if (f.exists()) {
-            f.delete();
+        if (wallpaper.wallpaperFile.exists()) {
+            wallpaper.wallpaperFile.delete();
+            wallpaper.cropFile.delete();
         }
         final long ident = Binder.clearCallingIdentity();
         try {
@@ -844,11 +968,10 @@
                     outParams.putInt("height", wallpaper.height);
                 }
                 wallpaper.callbacks.register(cb);
-                File f = new File(getWallpaperDir(wallpaperUserId), WALLPAPER);
-                if (!f.exists()) {
+                if (!wallpaper.cropFile.exists()) {
                     return null;
                 }
-                return ParcelFileDescriptor.open(f, MODE_READ_ONLY);
+                return ParcelFileDescriptor.open(wallpaper.cropFile, MODE_READ_ONLY);
             } catch (FileNotFoundException e) {
                 /* Shouldn't happen as we check to see if the file exists */
                 Slog.w(TAG, "Error getting wallpaper", e);
@@ -869,8 +992,8 @@
     }
 
     @Override
-    public ParcelFileDescriptor setWallpaper(String name, String callingPackage, Bundle extras,
-            int which) {
+    public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
+            Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
         if (which == 0) {
@@ -881,6 +1004,17 @@
             return null;
         }
 
+        // "null" means the no-op crop, preserving the full input image
+        if (cropHint == null) {
+            cropHint = new Rect(0, 0, 0, 0);
+        } else {
+            if (cropHint.isEmpty()
+                    || cropHint.left < 0
+                    || cropHint.top < 0) {
+                return null;
+            }
+        }
+
         synchronized (mLock) {
             if (DEBUG) Slog.v(TAG, "setWallpaper");
             int userId = UserHandle.getCallingUserId();
@@ -890,6 +1024,8 @@
                 ParcelFileDescriptor pfd = updateWallpaperBitmapLocked(name, wallpaper, extras);
                 if (pfd != null) {
                     wallpaper.imageWallpaperPending = true;
+                    wallpaper.setComplete = completion;
+                    wallpaper.cropHint.set(cropHint);
                 }
                 return pfd;
             } finally {
@@ -1196,6 +1332,12 @@
             out.attribute(null, "id", Integer.toString(wallpaper.wallpaperId));
             out.attribute(null, "width", Integer.toString(wallpaper.width));
             out.attribute(null, "height", Integer.toString(wallpaper.height));
+
+            out.attribute(null, "cropLeft", Integer.toString(wallpaper.cropHint.left));
+            out.attribute(null, "cropTop", Integer.toString(wallpaper.cropHint.top));
+            out.attribute(null, "cropRight", Integer.toString(wallpaper.cropHint.right));
+            out.attribute(null, "cropBottom", Integer.toString(wallpaper.cropHint.bottom));
+
             if (wallpaper.padding.left != 0) {
                 out.attribute(null, "paddingLeft", Integer.toString(wallpaper.padding.left));
             }
@@ -1208,6 +1350,7 @@
             if (wallpaper.padding.bottom != 0) {
                 out.attribute(null, "paddingBottom", Integer.toString(wallpaper.padding.bottom));
             }
+
             out.attribute(null, "name", wallpaper.name);
             if (wallpaper.wallpaperComponent != null
                     && !wallpaper.wallpaperComponent.equals(mImageWallpaper)) {
@@ -1304,6 +1447,10 @@
                         wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
                         wallpaper.height = Integer.parseInt(parser
                                 .getAttributeValue(null, "height"));
+                        wallpaper.cropHint.left = getAttributeInt(parser, "cropLeft", 0);
+                        wallpaper.cropHint.top = getAttributeInt(parser, "cropTop", 0);
+                        wallpaper.cropHint.right = getAttributeInt(parser, "cropRight", 0);
+                        wallpaper.cropHint.bottom = getAttributeInt(parser, "cropBottom", 0);
                         wallpaper.padding.left = getAttributeInt(parser, "paddingLeft", 0);
                         wallpaper.padding.top = getAttributeInt(parser, "paddingTop", 0);
                         wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
@@ -1322,6 +1469,7 @@
                         if (DEBUG) {
                             Slog.v(TAG, "mWidth:" + wallpaper.width);
                             Slog.v(TAG, "mHeight:" + wallpaper.height);
+                            Slog.v(TAG, "cropRect:" + wallpaper.cropHint);
                             Slog.v(TAG, "mName:" + wallpaper.name);
                             Slog.v(TAG, "mNextWallpaperComponent:"
                                     + wallpaper.nextWallpaperComponent);
@@ -1348,6 +1496,7 @@
         if (!success) {
             wallpaper.width = -1;
             wallpaper.height = -1;
+            wallpaper.cropHint.set(0, 0, 0, 0);
             wallpaper.padding.set(0, 0, 0, 0);
             wallpaper.name = "";
         } else {
@@ -1368,6 +1517,11 @@
         if (wallpaper.height < baseSize) {
             wallpaper.height = baseSize;
         }
+        // and crop, if not previously specified
+        if (wallpaper.cropHint.width() <= 0
+                || wallpaper.cropHint.height() <= 0) {
+            wallpaper.cropHint.set(0, 0, wallpaper.width, wallpaper.height);
+        }
     }
 
     private int getMaximumSizeDimension() {
@@ -1431,6 +1585,7 @@
         }
     }
 
+    // Restore the named resource bitmap to both source + crop files
     boolean restoreNamedResourceLocked(WallpaperData wallpaper) {
         if (wallpaper.name.length() > 4 && "res:".equals(wallpaper.name.substring(0, 4))) {
             String resName = wallpaper.name.substring(4);
@@ -1456,6 +1611,7 @@
                 int resId = -1;
                 InputStream res = null;
                 FileOutputStream fos = null;
+                FileOutputStream cos = null;
                 try {
                     Context c = mContext.createPackageContext(pkg, Context.CONTEXT_RESTRICTED);
                     Resources r = c.getResources();
@@ -1469,13 +1625,16 @@
                     res = r.openRawResource(resId);
                     if (wallpaper.wallpaperFile.exists()) {
                         wallpaper.wallpaperFile.delete();
+                        wallpaper.cropFile.delete();
                     }
                     fos = new FileOutputStream(wallpaper.wallpaperFile);
+                    cos = new FileOutputStream(wallpaper.cropFile);
 
                     byte[] buffer = new byte[32768];
                     int amt;
                     while ((amt=res.read(buffer)) > 0) {
                         fos.write(buffer, 0, amt);
+                        cos.write(buffer, 0, amt);
                     }
                     // mWallpaperObserver will notice the close and send the change broadcast
 
@@ -1491,8 +1650,12 @@
                     IoUtils.closeQuietly(res);
                     if (fos != null) {
                         FileUtils.sync(fos);
-                        IoUtils.closeQuietly(fos);
                     }
+                    if (cos != null) {
+                        FileUtils.sync(cos);
+                    }
+                    IoUtils.closeQuietly(fos);
+                    IoUtils.closeQuietly(cos);
                 }
             }
         }
@@ -1520,6 +1683,7 @@
                     pw.print(wallpaper.width);
                     pw.print(" mHeight=");
                     pw.println(wallpaper.height);
+                pw.print("  mCropHint="); pw.println(wallpaper.cropHint);
                 pw.print("  mPadding="); pw.println(wallpaper.padding);
                 pw.print("  mName=");  pw.println(wallpaper.name);
                 pw.print("  mWallpaperComponent="); pw.println(wallpaper.wallpaperComponent);
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index 0979cd3..66aa863 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -35,10 +35,10 @@
 
     static final boolean DEBUG_RESIZE = false;
     static final boolean DEBUG = false;
-    static final boolean DEBUG_ADD_REMOVE = false;
+    static final boolean DEBUG_ADD_REMOVE = true;
     static final boolean DEBUG_FOCUS = false;
     static final boolean DEBUG_FOCUS_LIGHT = DEBUG_FOCUS || false;
-    static final boolean DEBUG_ANIM = false;
+    static final boolean DEBUG_ANIM = true;
     static final boolean DEBUG_KEYGUARD = false;
     static final boolean DEBUG_LAYOUT = false;
     static final boolean DEBUG_LAYERS = false;
@@ -50,7 +50,7 @@
     static final boolean DEBUG_ORIENTATION = false;
     static final boolean DEBUG_APP_ORIENTATION = false;
     static final boolean DEBUG_CONFIGURATION = false;
-    static final boolean DEBUG_APP_TRANSITIONS = false;
+    static final boolean DEBUG_APP_TRANSITIONS = true;
     static final boolean DEBUG_STARTING_WINDOW = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 1214948..4dd2b4d 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -751,15 +751,16 @@
                     Math.min(mStableFrame.bottom, frame.bottom));
         }
 
-        mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
-                Math.max(mOverscanFrame.top - frame.top, 0),
-                Math.max(frame.right - mOverscanFrame.right, 0),
-                Math.max(frame.bottom - mOverscanFrame.bottom, 0));
-
-
+        if (!inFreeformWorkspace()) {
+            // Freeform windows can be positioned outside of the display frame, but that is not a
+            // reason to provide them with overscan insets.
+            mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
+                    Math.max(mOverscanFrame.top - frame.top, 0),
+                    Math.max(frame.right - mOverscanFrame.right, 0),
+                    Math.max(frame.bottom - mOverscanFrame.bottom, 0));
+        }
 
         if (mAttrs.type == TYPE_DOCK_DIVIDER) {
-
             // For the docked divider, we calculate the stable insets like a full-screen window
             // so it can use it to calculate the snap positions.
             mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
@@ -2238,7 +2239,8 @@
         }
         pw.print(prefix); pw.print("mHasSurface="); pw.print(mHasSurface);
                 pw.print(" mShownPosition="); mShownPosition.printShortString(pw);
-                pw.print(" isReadyForDisplay()="); pw.println(isReadyForDisplay());
+                pw.print(" isReadyForDisplay()="); pw.print(isReadyForDisplay());
+                pw.print(" hasSavedSurface()="); pw.println(hasSavedSurface());
         if (dumpAll) {
             pw.print(prefix); pw.print("mFrame="); mFrame.printShortString(pw);
                     pw.print(" last="); mLastFrame.printShortString(pw);
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index cffcc5d..428ab7a 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -567,6 +567,10 @@
 
     WindowSurfaceController createSurfaceLocked() {
         final WindowState w = mWin;
+        if (w.hasSavedSurface()) {
+            Slog.i(TAG, "***** createSurface: " + this + ": called when we had a saved surface");
+        }
+
         if (mSurfaceController == null) {
             if (DEBUG_ANIM || DEBUG_ORIENTATION) Slog.i(TAG,
                     "createSurface " + this + ": mDrawState=DRAW_PENDING");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 1b0660d..ca0b43a 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -509,6 +509,7 @@
         private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
         private static final String TAG_PARENT_ADMIN = "parent-admin";
         private static final String TAG_ORGANIZATION_COLOR = "organization-color";
+        private static final String TAG_ORGANIZATION_NAME = "organization-name";
 
         final DeviceAdminInfo info;
 
@@ -607,6 +608,9 @@
         static final int DEF_ORGANIZATION_COLOR = Color.GRAY;
         int organizationColor = DEF_ORGANIZATION_COLOR;
 
+        // Default title of confirm credentials screen
+        String organizationName = null;
+
         ActiveAdmin(DeviceAdminInfo _info, boolean parent) {
             info = _info;
             isParent = parent;
@@ -830,6 +834,11 @@
                 out.attribute(null, ATTR_VALUE, Integer.toString(organizationColor));
                 out.endTag(null, TAG_ORGANIZATION_COLOR);
             }
+            if (organizationName != null) {
+                out.startTag(null, TAG_ORGANIZATION_NAME);
+                out.text(organizationName);
+                out.endTag(null, TAG_ORGANIZATION_NAME);
+            }
         }
 
         void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -971,6 +980,13 @@
                 } else if (TAG_ORGANIZATION_COLOR.equals(tag)) {
                     organizationColor = Integer.parseInt(
                             parser.getAttributeValue(null, ATTR_VALUE));
+                } else if (TAG_ORGANIZATION_NAME.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        organizationName = parser.getText();
+                    } else {
+                        Log.w(LOG_TAG, "Missing text when loading organization name");
+                    }
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1179,6 +1195,12 @@
                 pw.print(prefix); pw.print("keepUninstalledPackages=");
                     pw.println(keepUninstalledPackages);
             }
+            pw.print(prefix); pw.print("organizationColor=");
+                    pw.println(organizationColor);
+            if (organizationName != null) {
+                pw.print(prefix); pw.print("organizationName=");
+                    pw.println(organizationName);
+            }
             pw.print(prefix); pw.println("userRestrictions:");
             UserRestrictionsUtils.dumpRestrictions(pw, prefix + "  ", userRestrictions);
             pw.print(prefix); pw.print("isParent=");
@@ -8096,11 +8118,12 @@
 
     @Override
     public void setOrganizationColor(@NonNull ComponentName who, int color) {
-        final int userHandle = mInjector.userHandleGetCallingUserId();
-        if (!mHasFeature || !isManagedProfile(userHandle)) {
+        if (!mHasFeature) {
             return;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        enforceManagedProfile(userHandle, "set organization color");
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8111,11 +8134,11 @@
 
     @Override
     public int getOrganizationColor(@NonNull ComponentName who) {
-        final int userHandle = mInjector.userHandleGetCallingUserId();
-        if (!mHasFeature || !isManagedProfile(userHandle)) {
+        if (!mHasFeature) {
             return ActiveAdmin.DEF_ORGANIZATION_COLOR;
         }
         Preconditions.checkNotNull(who, "ComponentName is null");
+        enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization color");
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -8125,10 +8148,11 @@
 
     @Override
     public int getOrganizationColorForUser(int userHandle) {
-        if (!mHasFeature || !isManagedProfile(userHandle)) {
+        if (!mHasFeature) {
             return ActiveAdmin.DEF_ORGANIZATION_COLOR;
         }
-        enforceCrossUsersPermission(userHandle);
+        enforceFullCrossUsersPermission(userHandle);
+        enforceManagedProfile(userHandle, "get organization color");
         synchronized (this) {
             ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
             return (profileOwner != null)
@@ -8138,6 +8162,53 @@
     }
 
     @Override
+    public void setOrganizationName(@NonNull ComponentName who, String text) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        enforceManagedProfile(userHandle, "set organization name");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            if (!TextUtils.equals(admin.organizationName, text)) {
+                admin.organizationName = TextUtils.nullIfEmpty(text);
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
+
+    @Override
+    public String getOrganizationName(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        enforceManagedProfile(mInjector.userHandleGetCallingUserId(), "get organization name");
+        synchronized(this) {
+            ActiveAdmin admin = getActiveAdminForCallerLocked(who,
+                    DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
+            return admin.organizationName;
+        }
+    }
+
+    @Override
+    public String getOrganizationNameForUser(int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        enforceFullCrossUsersPermission(userHandle);
+        enforceManagedProfile(userHandle, "get organization name");
+        synchronized (this) {
+            ActiveAdmin profileOwner = getProfileOwnerAdminLocked(userHandle);
+            return (profileOwner != null)
+                    ? profileOwner.organizationName
+                    : null;
+        }
+    }
+
+    @Override
     public void setAffiliationIds(ComponentName admin, List<String> ids) {
         final Set<String> affiliationIds = new ArraySet<String>(ids);
         final int callingUserId = mInjector.userHandleGetCallingUserId();
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index bfdac7e..77740387 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -145,6 +145,8 @@
     private boolean mScreenOn;
     private long mLastAppIdleParoledTime;
 
+    private volatile boolean mPendingOneTimeCheckIdleStates;
+
     long mScreenOnTime;
     long mLastScreenOnEventRealtime;
 
@@ -221,6 +223,10 @@
             synchronized (mLock) {
                 updateDisplayLocked();
             }
+
+            if (mPendingOneTimeCheckIdleStates) {
+                postOneTimeCheckIdleStates();
+            }
         } else if (phase == PHASE_BOOT_COMPLETED) {
             setAppIdleParoled(getContext().getSystemService(BatteryManager.class).isCharging());
         }
@@ -368,7 +374,13 @@
      * scheduling a series of repeating checkIdleStates each time we fired off one.
      */
     void postOneTimeCheckIdleStates() {
-        mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+        if (mDeviceIdleController == null) {
+            // Not booted yet; wait for it!
+            mPendingOneTimeCheckIdleStates = true;
+        } else {
+            mHandler.sendEmptyMessage(MSG_ONE_TIME_CHECK_IDLE_STATES);
+            mPendingOneTimeCheckIdleStates = false;
+        }
     }
 
     /** Check all running users' or specified user's apps to see if they enter an idle state. */
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index c65e8ba..84883d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -48,7 +48,9 @@
         mTimestamp = timestamp;
         mSleepTimeMs = sleepTimeMs;
         mIdleTimeMs = idleTimeMs;
-        System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+        if (txTimeMs != null) {
+            System.arraycopy(txTimeMs, 0, mTxTimeMs, 0, Math.min(txTimeMs.length, TX_POWER_LEVELS));
+        }
         mRxTimeMs = rxTimeMs;
         mEnergyUsed = energyUsed;
     }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
index 5dffa28..069fcbf 100644
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
@@ -16,8 +16,9 @@
 
 package com.android.internal.telephony;
 
-import android.os.Bundle;
+import com.android.internal.telephony.ITelephonyDebugSubscriber;
 
+import android.os.Bundle;
 
 /**
  * Interface used to interact with the Telephony debug service.
@@ -36,4 +37,7 @@
      * @param data optional
      */
     void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
+
+    void subscribe(in ITelephonyDebugSubscriber subscriber);
+    void unsubscribe(in ITelephonyDebugSubscriber subscriber);
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
new file mode 100644
index 0000000..64eb0f1
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+import com.android.internal.telephony.TelephonyEvent;
+
+import android.os.Bundle;
+
+/**
+ * Interface used to subscribe for events from Telephony debug service.
+ *
+ * {@hide}
+ */
+oneway interface ITelephonyDebugSubscriber {
+
+    /**
+     * Called when Telephony debug service has events.
+     */
+    void onEvents(in TelephonyEvent[] events);
+}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
new file mode 100644
index 0000000..1e74b31
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
new file mode 100644
index 0000000..26d466d
--- /dev/null
+++ b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2016 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.telephony;
+
+import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ *  A parcelable used in ITelephonyDebugSubscriber.aidl
+ */
+public class TelephonyEvent implements Parcelable {
+
+    final public long timestamp;
+    final public int phoneId;
+    final public int tag;
+    final public int param1;
+    final public int param2;
+    final public Bundle data;
+
+    public TelephonyEvent(long timestamp, int phoneId, int tag,
+            int param1, int param2, Bundle data) {
+        this.timestamp = timestamp;
+        this.phoneId = phoneId;
+        this.tag = tag;
+        this.param1 = param1;
+        this.param2 = param2;
+        this.data = data;
+    }
+
+    /** Implement the Parcelable interface */
+    public static final Parcelable.Creator<TelephonyEvent> CREATOR
+            = new Parcelable.Creator<TelephonyEvent> (){
+        public TelephonyEvent createFromParcel(Parcel source) {
+            final long timestamp = source.readLong();
+            final int phoneId = source.readInt();
+            final int tag = source.readInt();
+            final int param1 = source.readInt();
+            final int param2 = source.readInt();
+            final Bundle data = source.readBundle();
+            return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
+        }
+
+        public TelephonyEvent[] newArray(int size) {
+            return new TelephonyEvent[size];
+        }
+    };
+
+    /** Implement the Parcelable interface */
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    /** Implement the Parcelable interface */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        dest.writeLong(timestamp);
+        dest.writeInt(phoneId);
+        dest.writeInt(tag);
+        dest.writeInt(param1);
+        dest.writeInt(param2);
+        dest.writeBundle(data);
+    }
+
+    public String toString() {
+        return String.format("%d,%d,%d,%d,%d,%s",
+                timestamp, phoneId, tag, param1, param2, data);
+    }
+}
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
new file mode 100644
index 0000000..0e2467f
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_fill_state_list_simple.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#f00" android:state_pressed="true" />
+    <item android:color="#00f" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
new file mode 100644
index 0000000..7e6c8ce
--- /dev/null
+++ b/tests/VectorDrawableTest/res/color/vector_icon_stroke_state_list_simple.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not
+ * use this file except in compliance with the License. You may obtain a copy of
+ * the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+ * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+ * License for the specific language governing permissions and limitations under
+ * the License.
+ */
+-->
+<selector xmlns:android="http://schemas.android.com/apk/res/android">
+    <item android:color="#00f" android:state_pressed="true" />
+    <item android:color="#f00" />
+</selector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
new file mode 100644
index 0000000..9f08fe8
--- /dev/null
+++ b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_simple.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (C) 2016 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:height="64dp"
+        android:width="64dp"
+        android:viewportHeight="24"
+        android:viewportWidth="24" >
+
+    <path
+        android:fillColor="@color/vector_icon_fill_state_list_simple"
+        android:strokeColor="@color/vector_icon_stroke_state_list_simple"
+        android:strokeWidth="3"
+        android:pathData="M16.0,5.0c-1.955.0 -3.83,1.268 -4.5,3.0c-0.67-1.732 -2.547-3.0 -4.5-3.0C4.4570007,5.0 2.5,6.931999 2.5,9.5c0.0,3.529 3.793,6.258 9.0,11.5c5.207-5.242 9.0-7.971 9.0-11.5C20.5,6.931999 18.543,5.0 16.0,5.0z"/>
+
+</vector>
\ No newline at end of file
diff --git a/tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml b/tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
similarity index 100%
rename from tests/VectorDrawableTest/res/drawable/vector_icon_state_list.xml
rename to tests/VectorDrawableTest/res/drawable/vector_icon_state_list_theme.xml
diff --git a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
index a7da286..7172147 100644
--- a/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
+++ b/tests/VectorDrawableTest/src/com/android/test/dynamic/VectorDrawablePerformance.java
@@ -38,7 +38,8 @@
             R.drawable.vector_icon_gradient_1,
             R.drawable.vector_icon_gradient_2,
             R.drawable.vector_icon_gradient_3,
-            R.drawable.vector_icon_state_list,
+            R.drawable.vector_icon_state_list_simple,
+            R.drawable.vector_icon_state_list_theme,
             R.drawable.vector_drawable01,
             R.drawable.vector_drawable02,
             R.drawable.vector_drawable03,