Merge "Rename _BOOLEAN visual voicemail config keys to _BOOL" into nyc-dev
diff --git a/Android.mk b/Android.mk
index f875be2..1cde699 100644
--- a/Android.mk
+++ b/Android.mk
@@ -151,6 +151,7 @@
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
 	core/java/android/content/pm/IOnPermissionsChangeListener.aidl \
 	core/java/android/content/pm/IShortcutService.aidl \
+	core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl \
 	core/java/android/database/IContentObserver.aidl \
 	../av/camera/aidl/android/hardware/ICameraService.aidl \
 	../av/camera/aidl/android/hardware/ICameraServiceListener.aidl \
@@ -331,7 +332,7 @@
 	core/java/com/android/internal/textservice/ISpellCheckerSessionListener.aidl \
 	core/java/com/android/internal/textservice/ITextServicesManager.aidl \
 	core/java/com/android/internal/textservice/ITextServicesSessionListener.aidl \
-	core/java/com/android/internal/view/IDropPermissions.aidl \
+	core/java/com/android/internal/view/IDragAndDropPermissions.aidl \
 	core/java/com/android/internal/view/IInputContext.aidl \
 	core/java/com/android/internal/view/IInputContextCallback.aidl \
 	core/java/com/android/internal/view/IInputMethod.aidl \
@@ -401,6 +402,8 @@
 	media/java/android/media/tv/ITvInputServiceCallback.aidl \
 	media/java/android/media/tv/ITvInputSession.aidl \
 	media/java/android/media/tv/ITvInputSessionCallback.aidl \
+	media/java/android/media/tv/ITvRemoteProvider.aidl \
+	media/java/android/media/tv/ITvRemoteServiceInput.aidl \
 	media/java/android/service/media/IMediaBrowserService.aidl \
 	media/java/android/service/media/IMediaBrowserServiceCallbacks.aidl \
 	telecomm/java/com/android/internal/telecom/ICallScreeningAdapter.aidl \
diff --git a/api/current.txt b/api/current.txt
index 3c39ace..393de18 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -3424,6 +3424,7 @@
     method public void closeOptionsMenu();
     method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
     method public final deprecated void dismissDialog(int);
+    method public final void dismissKeyboardShortcutsHelper();
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method public boolean dispatchKeyEvent(android.view.KeyEvent);
     method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
@@ -3580,7 +3581,7 @@
     method public boolean releaseInstance();
     method public final deprecated void removeDialog(int);
     method public void reportFullyDrawn();
-    method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
+    method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
     method public final void requestKeyboardShortcutsHelper();
     method public final void requestPermissions(java.lang.String[], int);
     method public boolean requestVisibleBehind(boolean);
@@ -4926,6 +4927,7 @@
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
     field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
@@ -4946,7 +4948,6 @@
     field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
     field public static final java.lang.String EXTRA_TEXT = "android.text";
     field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
-    field public static final java.lang.String EXTRA_THREAD_TITLE = "android.threadTitle";
     field public static final java.lang.String EXTRA_TITLE = "android.title";
     field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
@@ -5199,17 +5200,14 @@
     field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
   }
 
-  public static final class Notification.MessagingStyle.Message implements android.os.Parcelable {
+  public static final class Notification.MessagingStyle.Message {
     ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
-    method public int describeContents();
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
     method public java.lang.CharSequence getSender();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
     method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.Notification.MessagingStyle.Message> CREATOR;
   }
 
   public static abstract class Notification.Style {
@@ -5244,6 +5242,7 @@
     method public int getCustomSizePreset();
     method public android.app.PendingIntent getDisplayIntent();
     method public int getGravity();
+    method public boolean getHintAmbientBigPicture();
     method public boolean getHintAvoidBackgroundClipping();
     method public boolean getHintContentIntentLaunchesActivity();
     method public boolean getHintHideIcon();
@@ -5260,6 +5259,7 @@
     method public android.app.Notification.WearableExtender setCustomSizePreset(int);
     method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
     method public android.app.Notification.WearableExtender setGravity(int);
+    method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
     method public android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
     method public android.app.Notification.WearableExtender setHintContentIntentLaunchesActivity(boolean);
     method public android.app.Notification.WearableExtender setHintHideIcon(boolean);
@@ -23024,6 +23024,7 @@
     method public boolean isRatingBlocked(android.media.tv.TvContentRating);
     method public void registerCallback(android.media.tv.TvInputManager.TvInputCallback, android.os.Handler);
     method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
+    method public void updateTvInputInfo(android.media.tv.TvInputInfo);
     field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
     field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
     field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
@@ -23061,7 +23062,6 @@
     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 static final void updateTvInputInfo(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";
   }
@@ -23243,24 +23243,6 @@
     ctor public MtpConstants();
     method public static boolean isAbstractObject(int);
     field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1
-    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
-    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
-    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
-    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
-    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
-    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
-    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
-    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
-    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
-    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
-    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
-    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
-    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
-    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
-    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
-    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
-    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
-    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
     field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984
     field public static final int FORMAT_AAC = 47363; // 0xb903
     field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03
@@ -23381,7 +23363,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
-    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
+    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal) throws java.io.IOException;
     method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
@@ -23393,10 +23375,11 @@
     method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
+    method public boolean isEventSupported(int);
+    method public boolean isOperationSupported(int);
   }
 
   public class MtpEvent {
-    ctor public MtpEvent();
     method public int getDevicePropCode();
     method public int getEventCode();
     method public int getObjectFormatCode();
@@ -23407,6 +23390,24 @@
     method public int getParameter3();
     method public int getStorageId();
     method public int getTransactionId();
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
   }
 
   public final class MtpObjectInfo {
@@ -29146,7 +29147,6 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
-    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
@@ -30331,7 +30331,7 @@
 
 package android.printservice {
 
-  public class CustomPrinterIconCallback {
+  public final class CustomPrinterIconCallback {
     method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
   }
 
@@ -40974,6 +40974,10 @@
     field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
   }
 
+  public final class DragAndDropPermissions {
+    method public void release();
+  }
+
   public class DragEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getAction();
@@ -40993,10 +40997,6 @@
     field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
   }
 
-  public final class DropPermissions {
-    method public void release();
-  }
-
   public class FocusFinder {
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
@@ -43530,7 +43530,7 @@
     ctor public Window(android.content.Context);
     method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void addFlags(int);
-    method public final void addFrameMetricsListener(android.view.Window.FrameMetricsListener, android.os.Handler);
+    method public final void addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler);
     method public void clearFlags(int);
     method public abstract void closeAllPanels();
     method public abstract void closePanel(int);
@@ -43582,7 +43582,7 @@
     method public abstract boolean performContextMenuIdentifierAction(int, int);
     method public abstract boolean performPanelIdentifierAction(int, int, int);
     method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
-    method public final void removeFrameMetricsListener(android.view.Window.FrameMetricsListener);
+    method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
     method public boolean requestFeature(int);
     method public abstract void restoreHierarchyState(android.os.Bundle);
     method public abstract android.os.Bundle saveHierarchyState();
@@ -43709,8 +43709,8 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.FrameMetricsListener {
-    method public abstract void onMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+  public static abstract interface Window.OnFrameMetricsAvailableListener {
+    method public abstract void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
   }
 
   public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
@@ -47464,7 +47464,7 @@
     method public void setChar(int, java.lang.String, char);
     method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
     method public void setChronometer(int, long, java.lang.String, boolean);
-    method public void setChronometerCountsDown(int, boolean);
+    method public void setChronometerCountDown(int, boolean);
     method public void setContentDescription(int, java.lang.CharSequence);
     method public void setDisplayedChild(int, int);
     method public void setDouble(int, java.lang.String, double);
@@ -58087,6 +58087,7 @@
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -59069,6 +59070,8 @@
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/removed.txt b/api/removed.txt
index 8c6abdc..de8a724 100644
--- a/api/removed.txt
+++ b/api/removed.txt
@@ -165,6 +165,31 @@
 
 }
 
+package android.mtp {
+
+  public final class MtpConstants {
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
+  }
+
+}
+
 package android.net {
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
diff --git a/api/system-current.txt b/api/system-current.txt
index 7c4d01c..dd22f82 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -46,11 +46,13 @@
     field public static final java.lang.String BIND_PRINT_SERVICE = "android.permission.BIND_PRINT_SERVICE";
     field public static final java.lang.String BIND_QUICK_SETTINGS_TILE = "android.permission.BIND_QUICK_SETTINGS_TILE";
     field public static final java.lang.String BIND_REMOTEVIEWS = "android.permission.BIND_REMOTEVIEWS";
+    field public static final java.lang.String BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE = "android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE";
     field public static final java.lang.String BIND_SCREENING_SERVICE = "android.permission.BIND_SCREENING_SERVICE";
     field public static final java.lang.String BIND_TELECOM_CONNECTION_SERVICE = "android.permission.BIND_TELECOM_CONNECTION_SERVICE";
     field public static final java.lang.String BIND_TEXT_SERVICE = "android.permission.BIND_TEXT_SERVICE";
     field public static final java.lang.String BIND_TRUST_AGENT = "android.permission.BIND_TRUST_AGENT";
     field public static final java.lang.String BIND_TV_INPUT = "android.permission.BIND_TV_INPUT";
+    field public static final java.lang.String BIND_TV_REMOTE_SERVICE = "android.permission.BIND_TV_REMOTE_SERVICE";
     field public static final java.lang.String BIND_VOICE_INTERACTION = "android.permission.BIND_VOICE_INTERACTION";
     field public static final java.lang.String BIND_VPN_SERVICE = "android.permission.BIND_VPN_SERVICE";
     field public static final java.lang.String BIND_VR_LISTENER_SERVICE = "android.permission.BIND_VR_LISTENER_SERVICE";
@@ -108,6 +110,7 @@
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GET_TOP_ACTIVITY_INFO = "android.permission.GET_TOP_ACTIVITY_INFO";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
+    field public static final java.lang.String GRANT_RUNTIME_PERMISSIONS = "android.permission.GRANT_RUNTIME_PERMISSIONS";
     field public static final java.lang.String HARDWARE_TEST = "android.permission.HARDWARE_TEST";
     field public static final java.lang.String HDMI_CEC = "android.permission.HDMI_CEC";
     field public static final java.lang.String INJECT_EVENTS = "android.permission.INJECT_EVENTS";
@@ -117,14 +120,17 @@
     field public static final java.lang.String INSTALL_SHORTCUT = "com.android.launcher.permission.INSTALL_SHORTCUT";
     field public static final java.lang.String INTENT_FILTER_VERIFICATION_AGENT = "android.permission.INTENT_FILTER_VERIFICATION_AGENT";
     field public static final java.lang.String INTERACT_ACROSS_USERS = "android.permission.INTERACT_ACROSS_USERS";
+    field public static final java.lang.String INTERACT_ACROSS_USERS_FULL = "android.permission.INTERACT_ACROSS_USERS_FULL";
     field public static final java.lang.String INTERNAL_SYSTEM_WINDOW = "android.permission.INTERNAL_SYSTEM_WINDOW";
     field public static final java.lang.String INTERNET = "android.permission.INTERNET";
     field public static final java.lang.String INVOKE_CARRIER_SETUP = "android.permission.INVOKE_CARRIER_SETUP";
     field public static final java.lang.String KILL_BACKGROUND_PROCESSES = "android.permission.KILL_BACKGROUND_PROCESSES";
+    field public static final java.lang.String KILL_UID = "android.permission.KILL_UID";
     field public static final java.lang.String LOCAL_MAC_ADDRESS = "android.permission.LOCAL_MAC_ADDRESS";
     field public static final java.lang.String LOCATION_HARDWARE = "android.permission.LOCATION_HARDWARE";
     field public static final java.lang.String LOOP_RADIO = "android.permission.LOOP_RADIO";
     field public static final java.lang.String MANAGE_ACTIVITY_STACKS = "android.permission.MANAGE_ACTIVITY_STACKS";
+    field public static final java.lang.String MANAGE_APP_OPS_RESTRICTIONS = "android.permission.MANAGE_APP_OPS_RESTRICTIONS";
     field public static final java.lang.String MANAGE_APP_TOKENS = "android.permission.MANAGE_APP_TOKENS";
     field public static final java.lang.String MANAGE_CA_CERTIFICATES = "android.permission.MANAGE_CA_CERTIFICATES";
     field public static final java.lang.String MANAGE_DEVICE_ADMINS = "android.permission.MANAGE_DEVICE_ADMINS";
@@ -222,6 +228,7 @@
     field public static final java.lang.String TETHER_PRIVILEGED = "android.permission.TETHER_PRIVILEGED";
     field public static final java.lang.String TRANSMIT_IR = "android.permission.TRANSMIT_IR";
     field public static final java.lang.String TV_INPUT_HARDWARE = "android.permission.TV_INPUT_HARDWARE";
+    field public static final java.lang.String TV_VIRTUAL_REMOTE_CONTROLLER = "android.permission.TV_VIRTUAL_REMOTE_CONTROLLER";
     field public static final java.lang.String UNINSTALL_SHORTCUT = "com.android.launcher.permission.UNINSTALL_SHORTCUT";
     field public static final java.lang.String UPDATE_APP_OPS_STATS = "android.permission.UPDATE_APP_OPS_STATS";
     field public static final java.lang.String UPDATE_DEVICE_STATS = "android.permission.UPDATE_DEVICE_STATS";
@@ -3541,6 +3548,7 @@
     method public boolean convertToTranslucent(android.app.Activity.TranslucentConversionListener, android.app.ActivityOptions);
     method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
     method public final deprecated void dismissDialog(int);
+    method public final void dismissKeyboardShortcutsHelper();
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method public boolean dispatchKeyEvent(android.view.KeyEvent);
     method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
@@ -3699,7 +3707,7 @@
     method public boolean releaseInstance();
     method public final deprecated void removeDialog(int);
     method public void reportFullyDrawn();
-    method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
+    method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
     method public final void requestKeyboardShortcutsHelper();
     method public final void requestPermissions(java.lang.String[], int);
     method public boolean requestVisibleBehind(boolean);
@@ -3821,6 +3829,7 @@
     method public static boolean isRunningInTestHarness();
     method public static boolean isUserAMonkey();
     method public void killBackgroundProcesses(java.lang.String);
+    method public void killUid(int, java.lang.String);
     method public void moveTaskToFront(int, int);
     method public void moveTaskToFront(int, int, android.os.Bundle);
     method public deprecated void restartPackage(java.lang.String);
@@ -4127,6 +4136,7 @@
     method public int noteProxyOp(java.lang.String, java.lang.String);
     method public int noteProxyOpNoThrow(java.lang.String, java.lang.String);
     method public static java.lang.String permissionToOp(java.lang.String);
+    method public void setUidMode(java.lang.String, int, int);
     method public int startOp(java.lang.String, int, java.lang.String);
     method public int startOpNoThrow(java.lang.String, int, java.lang.String);
     method public void startWatchingMode(java.lang.String, java.lang.String, android.app.AppOpsManager.OnOpChangedListener);
@@ -5060,6 +5070,7 @@
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
     field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
@@ -5080,7 +5091,6 @@
     field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
     field public static final java.lang.String EXTRA_TEXT = "android.text";
     field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
-    field public static final java.lang.String EXTRA_THREAD_TITLE = "android.threadTitle";
     field public static final java.lang.String EXTRA_TITLE = "android.title";
     field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTOGROUP_SUMMARY = 1024; // 0x400
@@ -5334,17 +5344,14 @@
     field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
   }
 
-  public static final class Notification.MessagingStyle.Message implements android.os.Parcelable {
+  public static final class Notification.MessagingStyle.Message {
     ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
-    method public int describeContents();
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
     method public java.lang.CharSequence getSender();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
     method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.Notification.MessagingStyle.Message> CREATOR;
   }
 
   public static abstract class Notification.Style {
@@ -5379,6 +5386,7 @@
     method public int getCustomSizePreset();
     method public android.app.PendingIntent getDisplayIntent();
     method public int getGravity();
+    method public boolean getHintAmbientBigPicture();
     method public boolean getHintAvoidBackgroundClipping();
     method public boolean getHintContentIntentLaunchesActivity();
     method public boolean getHintHideIcon();
@@ -5395,6 +5403,7 @@
     method public android.app.Notification.WearableExtender setCustomSizePreset(int);
     method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
     method public android.app.Notification.WearableExtender setGravity(int);
+    method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
     method public android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
     method public android.app.Notification.WearableExtender setHintContentIntentLaunchesActivity(boolean);
     method public android.app.Notification.WearableExtender setHintHideIcon(boolean);
@@ -8893,8 +8902,11 @@
     field public static final java.lang.String ACTION_MANAGED_PROFILE_REMOVED = "android.intent.action.MANAGED_PROFILE_REMOVED";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_UNAVAILABLE = "android.intent.action.MANAGED_PROFILE_UNAVAILABLE";
     field public static final java.lang.String ACTION_MANAGED_PROFILE_UNLOCKED = "android.intent.action.MANAGED_PROFILE_UNLOCKED";
+    field public static final java.lang.String ACTION_MANAGE_APP_PERMISSIONS = "android.intent.action.MANAGE_APP_PERMISSIONS";
     field public static final java.lang.String ACTION_MANAGE_NETWORK_USAGE = "android.intent.action.MANAGE_NETWORK_USAGE";
     field public static final java.lang.String ACTION_MANAGE_PACKAGE_STORAGE = "android.intent.action.MANAGE_PACKAGE_STORAGE";
+    field public static final java.lang.String ACTION_MANAGE_PERMISSIONS = "android.intent.action.MANAGE_PERMISSIONS";
+    field public static final java.lang.String ACTION_MANAGE_PERMISSION_APPS = "android.intent.action.MANAGE_PERMISSION_APPS";
     field public static final java.lang.String ACTION_MEDIA_BAD_REMOVAL = "android.intent.action.MEDIA_BAD_REMOVAL";
     field public static final java.lang.String ACTION_MEDIA_BUTTON = "android.intent.action.MEDIA_BUTTON";
     field public static final java.lang.String ACTION_MEDIA_CHECKING = "android.intent.action.MEDIA_CHECKING";
@@ -8938,6 +8950,7 @@
     field public static final java.lang.String ACTION_QUICK_VIEW = "android.intent.action.QUICK_VIEW";
     field public static final java.lang.String ACTION_REBOOT = "android.intent.action.REBOOT";
     field public static final java.lang.String ACTION_RESOLVE_EPHEMERAL_PACKAGE = "android.intent.action.RESOLVE_EPHEMERAL_PACKAGE";
+    field public static final java.lang.String ACTION_REVIEW_PERMISSIONS = "android.intent.action.REVIEW_PERMISSIONS";
     field public static final java.lang.String ACTION_RUN = "android.intent.action.RUN";
     field public static final java.lang.String ACTION_SCREEN_OFF = "android.intent.action.SCREEN_OFF";
     field public static final java.lang.String ACTION_SCREEN_ON = "android.intent.action.SCREEN_ON";
@@ -9044,6 +9057,7 @@
     field public static final java.lang.String EXTRA_LOCAL_ONLY = "android.intent.extra.LOCAL_ONLY";
     field public static final java.lang.String EXTRA_MIME_TYPES = "android.intent.extra.MIME_TYPES";
     field public static final java.lang.String EXTRA_NOT_UNKNOWN_SOURCE = "android.intent.extra.NOT_UNKNOWN_SOURCE";
+    field public static final java.lang.String EXTRA_ORIGINATING_UID = "android.intent.extra.ORIGINATING_UID";
     field public static final java.lang.String EXTRA_ORIGINATING_URI = "android.intent.extra.ORIGINATING_URI";
     field public static final java.lang.String EXTRA_PACKAGES = "android.intent.extra.PACKAGES";
     field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
@@ -9054,12 +9068,14 @@
     field public static final java.lang.String EXTRA_QUIET_MODE = "android.intent.extra.QUIET_MODE";
     field public static final java.lang.String EXTRA_REFERRER = "android.intent.extra.REFERRER";
     field public static final java.lang.String EXTRA_REFERRER_NAME = "android.intent.extra.REFERRER_NAME";
+    field public static final java.lang.String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
     field public static final java.lang.String EXTRA_REMOTE_INTENT_TOKEN = "android.intent.extra.remote_intent_token";
     field public static final java.lang.String EXTRA_REPLACEMENT_EXTRAS = "android.intent.extra.REPLACEMENT_EXTRAS";
     field public static final java.lang.String EXTRA_REPLACING = "android.intent.extra.REPLACING";
     field public static final java.lang.String EXTRA_RESTRICTIONS_BUNDLE = "android.intent.extra.restrictions_bundle";
     field public static final java.lang.String EXTRA_RESTRICTIONS_INTENT = "android.intent.extra.restrictions_intent";
     field public static final java.lang.String EXTRA_RESTRICTIONS_LIST = "android.intent.extra.restrictions_list";
+    field public static final java.lang.String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
     field public static final java.lang.String EXTRA_RESULT_RECEIVER = "android.intent.extra.RESULT_RECEIVER";
     field public static final java.lang.String EXTRA_RETURN_RESULT = "android.intent.extra.RETURN_RESULT";
     field public static final java.lang.String EXTRA_SHORTCUT_ICON = "android.intent.extra.shortcut.ICON";
@@ -10077,6 +10093,7 @@
     method public abstract android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public abstract java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
+    method public abstract java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method public abstract java.lang.String getInstallerPackageName(java.lang.String);
     method public abstract android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public abstract android.content.Intent getLaunchIntentForPackage(java.lang.String);
@@ -10228,6 +10245,13 @@
     field public static final java.lang.String FEATURE_WEBVIEW = "android.software.webview";
     field public static final java.lang.String FEATURE_WIFI = "android.hardware.wifi";
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
+    field public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 32; // 0x20
+    field public static final int FLAG_PERMISSION_POLICY_FIXED = 4; // 0x4
+    field public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 64; // 0x40
+    field public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 8; // 0x8
+    field public static final int FLAG_PERMISSION_SYSTEM_FIXED = 16; // 0x10
+    field public static final int FLAG_PERMISSION_USER_FIXED = 2; // 0x2
+    field public static final int FLAG_PERMISSION_USER_SET = 1; // 0x1
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
     field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
@@ -10524,6 +10548,20 @@
 
 }
 
+package android.content.pm.permission {
+
+  public final class RuntimePermissionPresentationInfo implements android.os.Parcelable {
+    ctor public RuntimePermissionPresentationInfo(java.lang.CharSequence, boolean, boolean);
+    method public int describeContents();
+    method public java.lang.CharSequence getLabel();
+    method public boolean isGranted();
+    method public boolean isStandard();
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.content.pm.permission.RuntimePermissionPresentationInfo> CREATOR;
+  }
+
+}
+
 package android.content.res {
 
   public class AssetFileDescriptor implements java.io.Closeable android.os.Parcelable {
@@ -24710,6 +24748,7 @@
     method public void removeBlockedRating(android.media.tv.TvContentRating);
     method public void setParentalControlsEnabled(boolean);
     method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
+    method public void updateTvInputInfo(android.media.tv.TvInputInfo);
     field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
     field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
     field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
@@ -24764,7 +24803,6 @@
     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 static final void updateTvInputInfo(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";
   }
@@ -24979,24 +25017,6 @@
     ctor public MtpConstants();
     method public static boolean isAbstractObject(int);
     field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1
-    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
-    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
-    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
-    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
-    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
-    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
-    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
-    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
-    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
-    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
-    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
-    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
-    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
-    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
-    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
-    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
-    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
-    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
     field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984
     field public static final int FORMAT_AAC = 47363; // 0xb903
     field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03
@@ -25117,7 +25137,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
-    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
+    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal) throws java.io.IOException;
     method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
@@ -25129,10 +25149,11 @@
     method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
+    method public boolean isEventSupported(int);
+    method public boolean isOperationSupported(int);
   }
 
   public class MtpEvent {
-    ctor public MtpEvent();
     method public int getDevicePropCode();
     method public int getEventCode();
     method public int getObjectFormatCode();
@@ -25143,6 +25164,24 @@
     method public int getParameter3();
     method public int getStorageId();
     method public int getTransactionId();
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
   }
 
   public final class MtpObjectInfo {
@@ -26011,33 +26050,11 @@
 
 package android.net.metrics {
 
-  public final class CaptivePortalCheckResultEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
-    method public int describeContents();
-    method public static void logEvent(int, int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.CaptivePortalCheckResultEvent> CREATOR;
-    field public final int netId;
-    field public final int result;
-  }
-
-  public final class CaptivePortalStateChangeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
-    ctor public CaptivePortalStateChangeEvent(int);
-    ctor public CaptivePortalStateChangeEvent(android.os.Parcel);
-    method public int describeContents();
-    method public static void logEvent(int);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.CaptivePortalStateChangeEvent> CREATOR;
-    field public static final int NETWORK_MONITOR_CONNECTED = 0; // 0x0
-    field public static final int NETWORK_MONITOR_DISCONNECTED = 1; // 0x1
-    field public static final int NETWORK_MONITOR_VALIDATED = 2; // 0x2
-    field public final int state;
-  }
-
-  public final class ConnectivityServiceChangeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class DefaultNetworkEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
     method public int describeContents();
     method public static void logEvent(int, int[], int, boolean, boolean);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.ConnectivityServiceChangeEvent> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.DefaultNetworkEvent> CREATOR;
     field public final int netId;
     field public final boolean prevIPv4;
     field public final boolean prevIPv6;
@@ -26111,12 +26128,16 @@
     field public static final int IPCE_IPMGR_PROVISIONING_FAIL = 4097; // 0x1001
     field public static final int IPCE_IPMGR_PROVISIONING_OK = 4096; // 0x1000
     field public static final int IPCE_IPRM_BASE = 0; // 0x0
-    field public static final int IPCE_IPRM_MESSAGE_RECEIVED = 1; // 0x1
-    field public static final int IPCE_IPRM_PROBE_RESULT = 0; // 0x0
-    field public static final int IPCE_IPRM_REACHABILITY_LOST = 2; // 0x2
+    field public static final int IPCE_IPRM_NUD_FAILED = 2; // 0x2
+    field public static final int IPCE_IPRM_PROBE_FAILURE = 1; // 0x1
+    field public static final int IPCE_IPRM_PROBE_STARTED = 0; // 0x0
+    field public static final int IPCE_IPRM_PROVISIONING_LOST = 3; // 0x3
     field public static final int IPCE_NETMON_BASE = 2048; // 0x800
+    field public static final int IPCE_NETMON_CAPPORT_FOUND = 2052; // 0x804
     field public static final int IPCE_NETMON_CHECK_RESULT = 2049; // 0x801
+    field public static final int IPCE_NETMON_PORTAL_PROBE = 2051; // 0x803
     field public static final int IPCE_NETMON_STATE_CHANGE = 2048; // 0x800
+    field public static final int IPCE_NETMON_VALIDATED = 2050; // 0x802
   }
 
   public final class IpManagerEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
@@ -26128,33 +26149,50 @@
     field public final java.lang.String ifName;
   }
 
-  public final class IpReachabilityMonitorLostEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class IpReachabilityEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public static void logEvent(java.lang.String);
+    method public static void logNudFailed(java.lang.String);
+    method public static void logProbeEvent(java.lang.String, int);
+    method public static void logProvisioningLost(java.lang.String);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorLostEvent> CREATOR;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityEvent> CREATOR;
+    field public static final int NUD_FAILED = 512; // 0x200
+    field public static final int PROBE = 256; // 0x100
+    field public static final int PROVISIONING_LOST = 768; // 0x300
+    field public final int eventType;
     field public final java.lang.String ifName;
   }
 
-  public final class IpReachabilityMonitorMessageEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class NetworkEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public static void logEvent(java.lang.String, java.lang.String, int, int);
+    method public static void logCaptivePortalFound(int, long);
+    method public static void logEvent(int, int);
+    method public static void logValidated(int, long);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorMessageEvent> CREATOR;
-    field public final java.lang.String destination;
-    field public final java.lang.String ifName;
-    field public final int msgType;
-    field public final int nudState;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.NetworkEvent> CREATOR;
+    field public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4; // 0x4
+    field public static final int NETWORK_CONNECTED = 1; // 0x1
+    field public static final int NETWORK_DISCONNECTED = 7; // 0x7
+    field public static final int NETWORK_LINGER = 5; // 0x5
+    field public static final int NETWORK_UNLINGER = 6; // 0x6
+    field public static final int NETWORK_VALIDATED = 2; // 0x2
+    field public static final int NETWORK_VALIDATION_FAILED = 3; // 0x3
+    field public final long durationMs;
+    field public final int eventType;
+    field public final int netId;
   }
 
-  public final class IpReachabilityMonitorProbeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
+  public final class ValidationProbeEvent extends android.net.metrics.IpConnectivityEvent implements android.os.Parcelable {
     method public int describeContents();
-    method public static void logEvent(java.lang.String, java.lang.String, boolean);
+    method public static void logEvent(int, long, int, int);
     method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.net.metrics.IpReachabilityMonitorProbeEvent> CREATOR;
-    field public final java.lang.String destination;
-    field public final java.lang.String ifName;
-    field public final boolean success;
+    field public static final android.os.Parcelable.Creator<android.net.metrics.ValidationProbeEvent> CREATOR;
+    field public static final int PROBE_HTTP = 0; // 0x0
+    field public static final int PROBE_HTTPS = 1; // 0x1
+    field public final long durationMs;
+    field public final int netId;
+    field public final int probeType;
+    field public final int returnCode;
   }
 
 }
@@ -30768,6 +30806,7 @@
     field public static final java.lang.String ID;
     field public static final java.lang.String MANUFACTURER;
     field public static final java.lang.String MODEL;
+    field public static final boolean PERMISSIONS_REVIEW_REQUIRED;
     field public static final java.lang.String PRODUCT;
     field public static final deprecated java.lang.String RADIO;
     field public static final java.lang.String SERIAL;
@@ -31574,7 +31613,6 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
-    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
     field public static final int USER_ACTIVITY_EVENT_ACCESSIBILITY = 3; // 0x3
     field public static final int USER_ACTIVITY_EVENT_BUTTON = 1; // 0x1
     field public static final int USER_ACTIVITY_EVENT_OTHER = 0; // 0x0
@@ -31648,6 +31686,19 @@
     method public abstract void onProgress(int);
   }
 
+  public final class RemoteCallback implements android.os.Parcelable {
+    ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener);
+    ctor public RemoteCallback(android.os.RemoteCallback.OnResultListener, android.os.Handler);
+    method public int describeContents();
+    method public void sendResult(android.os.Bundle);
+    method public void writeToParcel(android.os.Parcel, int);
+    field public static final android.os.Parcelable.Creator<android.os.RemoteCallback> CREATOR;
+  }
+
+  public static abstract interface RemoteCallback.OnResultListener {
+    method public abstract void onResult(android.os.Bundle);
+  }
+
   public class RemoteCallbackList {
     ctor public RemoteCallbackList();
     method public int beginBroadcast();
@@ -32124,6 +32175,19 @@
 
 }
 
+package android.permissionpresenterservice {
+
+  public abstract class RuntimePermissionPresenterService extends android.app.Service {
+    ctor public RuntimePermissionPresenterService();
+    method public final void attachBaseContext(android.content.Context);
+    method public final android.os.IBinder onBind(android.content.Intent);
+    method public abstract java.util.List<android.content.pm.permission.RuntimePermissionPresentationInfo> onGetAppPermissions(java.lang.String);
+    method public abstract java.util.List<android.content.pm.ApplicationInfo> onGetAppsUsingPermissions(boolean);
+    field public static final java.lang.String SERVICE_INTERFACE = "android.permissionpresenterservice.RuntimePermissionPresenterService";
+  }
+
+}
+
 package android.preference {
 
   public class CheckBoxPreference extends android.preference.TwoStatePreference {
@@ -32830,7 +32894,7 @@
 
 package android.printservice {
 
-  public class CustomPrinterIconCallback {
+  public final class CustomPrinterIconCallback {
     method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
   }
 
@@ -41033,6 +41097,7 @@
     method public android.graphics.drawable.Drawable getDrawable(java.lang.String, int, android.content.pm.ApplicationInfo);
     method public java.util.List<android.content.pm.ApplicationInfo> getInstalledApplications(int);
     method public java.util.List<android.content.pm.PackageInfo> getInstalledPackages(int);
+    method public java.util.List<android.content.pm.PackageInfo> getInstalledPackagesAsUser(int, int);
     method public java.lang.String getInstallerPackageName(java.lang.String);
     method public android.content.pm.InstrumentationInfo getInstrumentationInfo(android.content.ComponentName, int) throws android.content.pm.PackageManager.NameNotFoundException;
     method public android.content.Intent getLaunchIntentForPackage(java.lang.String);
@@ -43922,6 +43987,10 @@
     field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
   }
 
+  public final class DragAndDropPermissions {
+    method public void release();
+  }
+
   public class DragEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getAction();
@@ -43941,10 +44010,6 @@
     field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
   }
 
-  public final class DropPermissions {
-    method public void release();
-  }
-
   public class FocusFinder {
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
@@ -46478,7 +46543,7 @@
     ctor public Window(android.content.Context);
     method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void addFlags(int);
-    method public final void addFrameMetricsListener(android.view.Window.FrameMetricsListener, android.os.Handler);
+    method public final void addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler);
     method public void clearFlags(int);
     method public abstract void closeAllPanels();
     method public abstract void closePanel(int);
@@ -46530,7 +46595,7 @@
     method public abstract boolean performContextMenuIdentifierAction(int, int);
     method public abstract boolean performPanelIdentifierAction(int, int, int);
     method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
-    method public final void removeFrameMetricsListener(android.view.Window.FrameMetricsListener);
+    method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
     method public boolean requestFeature(int);
     method public abstract void restoreHierarchyState(android.os.Bundle);
     method public abstract android.os.Bundle saveHierarchyState();
@@ -46658,8 +46723,8 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.FrameMetricsListener {
-    method public abstract void onMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+  public static abstract interface Window.OnFrameMetricsAvailableListener {
+    method public abstract void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
   }
 
   public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
@@ -50770,7 +50835,7 @@
     method public void setChar(int, java.lang.String, char);
     method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
     method public void setChronometer(int, long, java.lang.String, boolean);
-    method public void setChronometerCountsDown(int, boolean);
+    method public void setChronometerCountDown(int, boolean);
     method public void setContentDescription(int, java.lang.CharSequence);
     method public void setDisplayedChild(int, int);
     method public void setDouble(int, java.lang.String, double);
@@ -61393,6 +61458,7 @@
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -62375,6 +62441,8 @@
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/system-removed.txt b/api/system-removed.txt
index 95734c1..844604c 100644
--- a/api/system-removed.txt
+++ b/api/system-removed.txt
@@ -163,6 +163,31 @@
 
 }
 
+package android.mtp {
+
+  public final class MtpConstants {
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
+  }
+
+}
+
 package android.net {
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
diff --git a/api/test-current.txt b/api/test-current.txt
index 592108d..c919021 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -3424,6 +3424,7 @@
     method public void closeOptionsMenu();
     method public android.app.PendingIntent createPendingResult(int, android.content.Intent, int);
     method public final deprecated void dismissDialog(int);
+    method public final void dismissKeyboardShortcutsHelper();
     method public boolean dispatchGenericMotionEvent(android.view.MotionEvent);
     method public boolean dispatchKeyEvent(android.view.KeyEvent);
     method public boolean dispatchKeyShortcutEvent(android.view.KeyEvent);
@@ -3580,7 +3581,7 @@
     method public boolean releaseInstance();
     method public final deprecated void removeDialog(int);
     method public void reportFullyDrawn();
-    method public android.view.DropPermissions requestDropPermissions(android.view.DragEvent);
+    method public android.view.DragAndDropPermissions requestDragAndDropPermissions(android.view.DragEvent);
     method public final void requestKeyboardShortcutsHelper();
     method public final void requestPermissions(java.lang.String[], int);
     method public boolean requestVisibleBehind(boolean);
@@ -4926,6 +4927,7 @@
     field public static final java.lang.String EXTRA_BIG_TEXT = "android.bigText";
     field public static final java.lang.String EXTRA_CHRONOMETER_COUNTS_DOWN = "android.chronometerCountsDown";
     field public static final java.lang.String EXTRA_COMPACT_ACTIONS = "android.compactActions";
+    field public static final java.lang.String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
     field public static final java.lang.String EXTRA_INFO_TEXT = "android.infoText";
     field public static final java.lang.String EXTRA_LARGE_ICON = "android.largeIcon";
     field public static final java.lang.String EXTRA_LARGE_ICON_BIG = "android.largeIcon.big";
@@ -4946,7 +4948,6 @@
     field public static final java.lang.String EXTRA_TEMPLATE = "android.template";
     field public static final java.lang.String EXTRA_TEXT = "android.text";
     field public static final java.lang.String EXTRA_TEXT_LINES = "android.textLines";
-    field public static final java.lang.String EXTRA_THREAD_TITLE = "android.threadTitle";
     field public static final java.lang.String EXTRA_TITLE = "android.title";
     field public static final java.lang.String EXTRA_TITLE_BIG = "android.title.big";
     field public static final int FLAG_AUTO_CANCEL = 16; // 0x10
@@ -5199,17 +5200,14 @@
     field public static final int MAXIMUM_RETAINED_MESSAGES = 25; // 0x19
   }
 
-  public static final class Notification.MessagingStyle.Message implements android.os.Parcelable {
+  public static final class Notification.MessagingStyle.Message {
     ctor public Notification.MessagingStyle.Message(java.lang.CharSequence, long, java.lang.CharSequence);
-    method public int describeContents();
     method public java.lang.String getDataMimeType();
     method public android.net.Uri getDataUri();
     method public java.lang.CharSequence getSender();
     method public java.lang.CharSequence getText();
     method public long getTimestamp();
     method public android.app.Notification.MessagingStyle.Message setData(java.lang.String, android.net.Uri);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.app.Notification.MessagingStyle.Message> CREATOR;
   }
 
   public static abstract class Notification.Style {
@@ -5244,6 +5242,7 @@
     method public int getCustomSizePreset();
     method public android.app.PendingIntent getDisplayIntent();
     method public int getGravity();
+    method public boolean getHintAmbientBigPicture();
     method public boolean getHintAvoidBackgroundClipping();
     method public boolean getHintContentIntentLaunchesActivity();
     method public boolean getHintHideIcon();
@@ -5260,6 +5259,7 @@
     method public android.app.Notification.WearableExtender setCustomSizePreset(int);
     method public android.app.Notification.WearableExtender setDisplayIntent(android.app.PendingIntent);
     method public android.app.Notification.WearableExtender setGravity(int);
+    method public android.app.Notification.WearableExtender setHintAmbientBigPicture(boolean);
     method public android.app.Notification.WearableExtender setHintAvoidBackgroundClipping(boolean);
     method public android.app.Notification.WearableExtender setHintContentIntentLaunchesActivity(boolean);
     method public android.app.Notification.WearableExtender setHintHideIcon(boolean);
@@ -23092,6 +23092,7 @@
     method public boolean isRatingBlocked(android.media.tv.TvContentRating);
     method public void registerCallback(android.media.tv.TvInputManager.TvInputCallback, android.os.Handler);
     method public void unregisterCallback(android.media.tv.TvInputManager.TvInputCallback);
+    method public void updateTvInputInfo(android.media.tv.TvInputInfo);
     field public static final java.lang.String ACTION_BLOCKED_RATINGS_CHANGED = "android.media.tv.action.BLOCKED_RATINGS_CHANGED";
     field public static final java.lang.String ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED = "android.media.tv.action.PARENTAL_CONTROLS_ENABLED_CHANGED";
     field public static final java.lang.String ACTION_QUERY_CONTENT_RATING_SYSTEMS = "android.media.tv.action.QUERY_CONTENT_RATING_SYSTEMS";
@@ -23129,7 +23130,6 @@
     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 static final void updateTvInputInfo(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";
   }
@@ -23311,24 +23311,6 @@
     ctor public MtpConstants();
     method public static boolean isAbstractObject(int);
     field public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 1; // 0x1
-    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
-    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
-    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
-    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
-    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
-    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
-    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
-    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
-    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
-    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
-    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
-    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
-    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
-    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
-    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
-    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
-    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
-    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
     field public static final int FORMAT_3GP_CONTAINER = 47492; // 0xb984
     field public static final int FORMAT_AAC = 47363; // 0xb903
     field public static final int FORMAT_ABSTRACT_AUDIO_ALBUM = 47619; // 0xba03
@@ -23449,7 +23431,7 @@
     method public boolean importFile(int, java.lang.String);
     method public boolean importFile(int, android.os.ParcelFileDescriptor);
     method public boolean open(android.hardware.usb.UsbDeviceConnection);
-    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal);
+    method public android.mtp.MtpEvent readEvent(android.os.CancellationSignal) throws java.io.IOException;
     method public boolean sendObject(int, long, android.os.ParcelFileDescriptor);
     method public android.mtp.MtpObjectInfo sendObjectInfo(android.mtp.MtpObjectInfo);
   }
@@ -23461,10 +23443,11 @@
     method public final int[] getOperationsSupported();
     method public final java.lang.String getSerialNumber();
     method public final java.lang.String getVersion();
+    method public boolean isEventSupported(int);
+    method public boolean isOperationSupported(int);
   }
 
   public class MtpEvent {
-    ctor public MtpEvent();
     method public int getDevicePropCode();
     method public int getEventCode();
     method public int getObjectFormatCode();
@@ -23475,6 +23458,24 @@
     method public int getParameter3();
     method public int getStorageId();
     method public int getTransactionId();
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
   }
 
   public final class MtpObjectInfo {
@@ -29214,7 +29215,6 @@
     field public static final int RELEASE_FLAG_WAIT_FOR_NO_PROXIMITY = 1; // 0x1
     field public static final deprecated int SCREEN_BRIGHT_WAKE_LOCK = 10; // 0xa
     field public static final deprecated int SCREEN_DIM_WAKE_LOCK = 6; // 0x6
-    field public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 256; // 0x100
   }
 
   public final class PowerManager.WakeLock {
@@ -30403,7 +30403,7 @@
 
 package android.printservice {
 
-  public class CustomPrinterIconCallback {
+  public final class CustomPrinterIconCallback {
     method public boolean onCustomPrinterIconLoaded(android.graphics.drawable.Icon);
   }
 
@@ -41051,6 +41051,10 @@
     field public static final android.os.Parcelable.Creator<android.view.Display.Mode> CREATOR;
   }
 
+  public final class DragAndDropPermissions {
+    method public void release();
+  }
+
   public class DragEvent implements android.os.Parcelable {
     method public int describeContents();
     method public int getAction();
@@ -41070,10 +41074,6 @@
     field public static final android.os.Parcelable.Creator<android.view.DragEvent> CREATOR;
   }
 
-  public final class DropPermissions {
-    method public void release();
-  }
-
   public class FocusFinder {
     method public android.view.View findNearestTouchable(android.view.ViewGroup, int, int, int, int[]);
     method public final android.view.View findNextFocus(android.view.ViewGroup, android.view.View, int);
@@ -43607,7 +43607,7 @@
     ctor public Window(android.content.Context);
     method public abstract void addContentView(android.view.View, android.view.ViewGroup.LayoutParams);
     method public void addFlags(int);
-    method public final void addFrameMetricsListener(android.view.Window.FrameMetricsListener, android.os.Handler);
+    method public final void addOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener, android.os.Handler);
     method public void clearFlags(int);
     method public abstract void closeAllPanels();
     method public abstract void closePanel(int);
@@ -43659,7 +43659,7 @@
     method public abstract boolean performContextMenuIdentifierAction(int, int);
     method public abstract boolean performPanelIdentifierAction(int, int, int);
     method public abstract boolean performPanelShortcut(int, int, android.view.KeyEvent, int);
-    method public final void removeFrameMetricsListener(android.view.Window.FrameMetricsListener);
+    method public final void removeOnFrameMetricsAvailableListener(android.view.Window.OnFrameMetricsAvailableListener);
     method public boolean requestFeature(int);
     method public abstract void restoreHierarchyState(android.os.Bundle);
     method public abstract android.os.Bundle saveHierarchyState();
@@ -43786,8 +43786,8 @@
     method public abstract android.view.ActionMode onWindowStartingActionMode(android.view.ActionMode.Callback, int);
   }
 
-  public static abstract interface Window.FrameMetricsListener {
-    method public abstract void onMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
+  public static abstract interface Window.OnFrameMetricsAvailableListener {
+    method public abstract void onFrameMetricsAvailable(android.view.Window, android.view.FrameMetrics, int);
   }
 
   public static abstract interface Window.OnRestrictedCaptionAreaChangedListener {
@@ -47541,7 +47541,7 @@
     method public void setChar(int, java.lang.String, char);
     method public void setCharSequence(int, java.lang.String, java.lang.CharSequence);
     method public void setChronometer(int, long, java.lang.String, boolean);
-    method public void setChronometerCountsDown(int, boolean);
+    method public void setChronometerCountDown(int, boolean);
     method public void setContentDescription(int, java.lang.CharSequence);
     method public void setDisplayedChild(int, int);
     method public void setDouble(int, java.lang.String, double);
@@ -58165,6 +58165,7 @@
     method public java.lang.Object clone();
     method public java.util.Set<java.util.Map.Entry<K, V>> entrySet();
     method public void forEach(java.util.function.BiConsumer<? super K, ? super V>);
+    method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
   }
 
   public class IllegalFormatCodePointException extends java.util.IllegalFormatException {
@@ -59147,6 +59148,8 @@
     method public java.util.NavigableSet<K> navigableKeySet();
     method public java.util.Map.Entry<K, V> pollFirstEntry();
     method public java.util.Map.Entry<K, V> pollLastEntry();
+    method public boolean replace(K, V, V);
+    method public V replace(K, V);
     method public void replaceAll(java.util.function.BiFunction<? super K, ? super V, ? extends V>);
     method public java.util.NavigableMap<K, V> subMap(K, boolean, K, boolean);
     method public java.util.SortedMap<K, V> subMap(K, K);
diff --git a/api/test-removed.txt b/api/test-removed.txt
index 8c6abdc..de8a724 100644
--- a/api/test-removed.txt
+++ b/api/test-removed.txt
@@ -165,6 +165,31 @@
 
 }
 
+package android.mtp {
+
+  public final class MtpConstants {
+    field public static final int EVENT_CANCEL_TRANSACTION = 16385; // 0x4001
+    field public static final int EVENT_CAPTURE_COMPLETE = 16397; // 0x400d
+    field public static final int EVENT_DEVICE_INFO_CHANGED = 16392; // 0x4008
+    field public static final int EVENT_DEVICE_PROP_CHANGED = 16390; // 0x4006
+    field public static final int EVENT_DEVICE_RESET = 16395; // 0x400b
+    field public static final int EVENT_OBJECT_ADDED = 16386; // 0x4002
+    field public static final int EVENT_OBJECT_INFO_CHANGED = 16391; // 0x4007
+    field public static final int EVENT_OBJECT_PROP_CHANGED = 51201; // 0xc801
+    field public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 51202; // 0xc802
+    field public static final int EVENT_OBJECT_REFERENCES_CHANGED = 51203; // 0xc803
+    field public static final int EVENT_OBJECT_REMOVED = 16387; // 0x4003
+    field public static final int EVENT_REQUEST_OBJECT_TRANSFER = 16393; // 0x4009
+    field public static final int EVENT_STORAGE_INFO_CHANGED = 16396; // 0x400c
+    field public static final int EVENT_STORE_ADDED = 16388; // 0x4004
+    field public static final int EVENT_STORE_FULL = 16394; // 0x400a
+    field public static final int EVENT_STORE_REMOVED = 16389; // 0x4005
+    field public static final int EVENT_UNDEFINED = 16384; // 0x4000
+    field public static final int EVENT_UNREPORTED_STATUS = 16398; // 0x400e
+  }
+
+}
+
 package android.net {
 
   public class SSLCertificateSocketFactory extends javax.net.ssl.SSLSocketFactory {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 9bd648f..0149952 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -85,8 +85,8 @@
 import android.view.ContextMenu;
 import android.view.ContextMenu.ContextMenuInfo;
 import android.view.ContextThemeWrapper;
+import android.view.DragAndDropPermissions;
 import android.view.DragEvent;
-import android.view.DropPermissions;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -721,6 +721,10 @@
 
     private static final String REQUEST_PERMISSIONS_WHO_PREFIX = "@android:requestPermissions:";
 
+    private static final String KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME = "com.android.systemui";
+    private static final String KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME =
+            "com.android.systemui.statusbar.KeyboardShortcutsReceiver";
+
     private static class ManagedDialog {
         Dialog mDialog;
         Bundle mArgs;
@@ -1682,8 +1686,18 @@
      */
     public final void requestKeyboardShortcutsHelper() {
         Intent intent = new Intent(Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS);
-        intent.setComponent(new ComponentName("com.android.systemui",
-                "com.android.systemui.statusbar.KeyboardShortcutsReceiver"));
+        intent.setComponent(new ComponentName(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME,
+                KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME));
+        sendBroadcast(intent);
+    }
+
+    /**
+     * Dismiss the Keyboard Shortcuts screen.
+     */
+    public final void dismissKeyboardShortcutsHelper() {
+        Intent intent = new Intent(Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS);
+        intent.setComponent(new ComponentName(KEYBOARD_SHORTCUTS_RECEIVER_PKG_NAME,
+                KEYBOARD_SHORTCUTS_RECEIVER_CLASS_NAME));
         sendBroadcast(intent);
     }
 
@@ -1693,11 +1707,6 @@
         if (menu == null) {
           return;
         }
-        final InputDevice inputDevice = InputManager.getInstance().getInputDevice(deviceId);
-        if (inputDevice == null) {
-            return;
-        }
-        final KeyCharacterMap keyCharacterMap = inputDevice.getKeyCharacterMap();
         KeyboardShortcutGroup group = null;
         int menuSize = menu.size();
         for (int i = 0; i < menuSize; ++i) {
@@ -6505,16 +6514,16 @@
     }
 
     /**
-     * Create {@link DropPermissions} object bound to this activity and controlling the access
-     * permissions for content URIs associated with the {@link DragEvent}.
+     * Create {@link DragAndDropPermissions} object bound to this activity and controlling the
+     * access permissions for content URIs associated with the {@link DragEvent}.
      * @param event Drag event
-     * @return The DropPermissions object used to control access to the content URIs. Null if
-     * no content URIs are associated with the event or if permissions could not be granted.
+     * @return The {@link DragAndDropPermissions} object used to control access to the content URIs.
+     * Null if no content URIs are associated with the event or if permissions could not be granted.
      */
-    public DropPermissions requestDropPermissions(DragEvent event) {
-        DropPermissions dropPermissions = DropPermissions.obtain(event);
-        if (dropPermissions != null && dropPermissions.take(getActivityToken())) {
-            return dropPermissions;
+    public DragAndDropPermissions requestDragAndDropPermissions(DragEvent event) {
+        DragAndDropPermissions dragAndDropPermissions = DragAndDropPermissions.obtain(event);
+        if (dragAndDropPermissions != null && dragAndDropPermissions.take(getActivityToken())) {
+            return dragAndDropPermissions;
         }
         return null;
     }
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 424d355..d440017 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -31,7 +31,6 @@
 import android.os.IBinder;
 import android.os.ParcelFileDescriptor;
 
-import android.util.Log;
 import com.android.internal.app.procstats.ProcessStats;
 import com.android.internal.os.TransferPipe;
 import com.android.internal.util.FastPrintWriter;
@@ -63,7 +62,6 @@
 import android.text.TextUtils;
 import android.util.DisplayMetrics;
 import android.util.Size;
-import android.util.Slog;
 
 import org.xmlpull.v1.XmlSerializer;
 
@@ -126,6 +124,19 @@
     public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
 
     /**
+     * Result for IActivityManager.startVoiceActivity: active session is currently hidden.
+     * @hide
+     */
+    public static final int START_VOICE_HIDDEN_SESSION = -10;
+
+    /**
+     * Result for IActivityManager.startVoiceActivity: active session does not match
+     * the requesting token.
+     * @hide
+     */
+    public static final int START_VOICE_NOT_ACTIVE_SESSION = -9;
+
+    /**
      * Result for IActivityManager.startActivity: trying to start a background user
      * activity that shouldn't be displayed for all users.
      * @hide
@@ -683,6 +694,14 @@
         public static boolean activitiesCanRequestVisibleBehind(int stackId) {
             return stackId == FULLSCREEN_WORKSPACE_STACK_ID;
         }
+
+        /**
+         * Returns true if this stack may be scaled without resizing,
+         * and windows within may need to be configured as such.
+         */
+        public static boolean windowsAreScaleable(int stackId) {
+            return stackId == PINNED_STACK_ID;
+        }
     }
 
     /**
@@ -2347,8 +2366,10 @@
         public String[] taskNames;
         public Rect[] taskBounds;
         public int[] taskUserIds;
+        public ComponentName topActivity;
         public int displayId;
         public int userId;
+        public boolean visible;
 
         @Override
         public int describeContents() {
@@ -2375,6 +2396,13 @@
             dest.writeIntArray(taskUserIds);
             dest.writeInt(displayId);
             dest.writeInt(userId);
+            dest.writeInt(visible ? 1 : 0);
+            if (topActivity != null) {
+                dest.writeInt(1);
+                topActivity.writeToParcel(dest, 0);
+            } else {
+                dest.writeInt(0);
+            }
         }
 
         public void readFromParcel(Parcel source) {
@@ -2397,6 +2425,10 @@
             taskUserIds = source.createIntArray();
             displayId = source.readInt();
             userId = source.readInt();
+            visible = source.readInt() > 0;
+            if (source.readInt() > 0) {
+                topActivity = ComponentName.readFromParcel(source);
+            }
         }
 
         public static final Creator<StackInfo> CREATOR = new Creator<StackInfo>() {
@@ -2432,6 +2464,10 @@
                             sb.append(" bounds="); sb.append(taskBounds[i].toShortString());
                         }
                         sb.append(" userId=").append(taskUserIds[i]);
+                        sb.append(" visible=").append(visible);
+                        if (topActivity != null) {
+                            sb.append(" topActivity=").append(topActivity);
+                        }
                         sb.append("\n");
             }
             return sb.toString();
@@ -3074,6 +3110,7 @@
      *
      * @hide
      */
+    @SystemApi
     @RequiresPermission(Manifest.permission.KILL_UID)
     public void killUid(int uid, String reason) {
         try {
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index ae2ca84..a3f3b2b3 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2959,6 +2959,13 @@
             reply.writeNoException();
             return true;
         }
+        case START_CONFIRM_DEVICE_CREDENTIAL_INTENT: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final Intent intent = Intent.CREATOR.createFromParcel(data);
+            startConfirmDeviceCredentialIntent(intent);
+            reply.writeNoException();
+            return true;
+        }
         }
 
         return super.onTransact(code, data, reply, flags);
@@ -6931,5 +6938,16 @@
         reply.recycle();
     }
 
+    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        intent.writeToParcel(data, 0);
+        mRemote.transact(START_CONFIRM_DEVICE_CREDENTIAL_INTENT, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+
     private IBinder mRemote;
 }
diff --git a/core/java/android/app/AlarmManager.java b/core/java/android/app/AlarmManager.java
index e4fff9d..02dcc5c 100644
--- a/core/java/android/app/AlarmManager.java
+++ b/core/java/android/app/AlarmManager.java
@@ -33,7 +33,6 @@
 import libcore.util.ZoneInfoDB;
 
 import java.io.IOException;
-import java.lang.ref.WeakReference;
 import java.util.WeakHashMap;
 
 /**
@@ -245,12 +244,7 @@
 
     // Tracking of the OnAlarmListener -> wrapper mapping, for cancel() support.
     // Access is synchronized on the AlarmManager class object.
-    //
-    // These are weak references so that we don't leak listener references if, for
-    // example, the pending-alarm messages are posted to a HandlerThread that is
-    // disposed of prior to alarm delivery.  The underlying messages will be GC'd
-    // but this static reference would still persist, orphaned, never deallocated.
-    private static WeakHashMap<OnAlarmListener, WeakReference<ListenerWrapper>> sWrappers;
+    private static WeakHashMap<OnAlarmListener, ListenerWrapper> sWrappers;
 
     /**
      * package private on purpose
@@ -637,16 +631,14 @@
         if (listener != null) {
             synchronized (AlarmManager.class) {
                 if (sWrappers == null) {
-                    sWrappers = new WeakHashMap<OnAlarmListener, WeakReference<ListenerWrapper>>();
+                    sWrappers = new WeakHashMap<OnAlarmListener, ListenerWrapper>();
                 }
 
-                WeakReference<ListenerWrapper> wrapperRef = sWrappers.get(listener);
-                // no existing wrapper *or* we've lost our weak ref to it => build a new one
-                if (wrapperRef == null ||
-                        (recipientWrapper = wrapperRef.get()) == null) {
+                recipientWrapper = sWrappers.get(listener);
+                // no existing wrapper => build a new one
+                if (recipientWrapper == null) {
                     recipientWrapper = new ListenerWrapper(listener);
-                    wrapperRef = new WeakReference<ListenerWrapper>(recipientWrapper);
-                    sWrappers.put(listener, wrapperRef);
+                    sWrappers.put(listener, recipientWrapper);
                 }
             }
 
@@ -906,11 +898,7 @@
         ListenerWrapper wrapper = null;
         synchronized (AlarmManager.class) {
             if (sWrappers != null) {
-                final WeakReference<ListenerWrapper> wrapperRef;
-                wrapperRef = sWrappers.get(listener);
-                if (wrapperRef != null) {
-                    wrapper = wrapperRef.get();
-                }
+                wrapper = sWrappers.get(listener);
             }
         }
 
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 64586a6..783c37d 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1256,7 +1256,16 @@
         }
     }
 
-    /** @hide */
+    /**
+     * Sets given app op in the specified mode for app ops in the UID.
+     * This applies to all apps currently in the UID or installed in
+     * this UID in the future.
+     *
+     * @param code The app op.
+     * @param uid The UID for which to set the app.
+     * @param mode The app op mode to set.
+     * @hide
+     */
     public void setUidMode(int code, int uid, int mode) {
         try {
             mService.setUidMode(code, uid, mode);
@@ -1265,6 +1274,25 @@
         }
     }
 
+    /**
+     * Sets given app op in the specified mode for app ops in the UID.
+     * This applies to all apps currently in the UID or installed in
+     * this UID in the future.
+     *
+     * @param appOp The app op.
+     * @param uid The UID for which to set the app.
+     * @param mode The app op mode to set.
+     * @hide
+     */
+    @SystemApi
+    public void setUidMode(String appOp, int uid, int mode) {
+        try {
+            mService.setUidMode(AppOpsManager.strOpToOp(appOp), uid, mode);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     /** @hide */
     public void setUserRestriction(int code, boolean restricted, IBinder token) {
         setUserRestriction(code, restricted, token, /*exceptionPackages*/null);
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index bf56f25..87511ee 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -441,7 +441,7 @@
 
     /** @hide */
     @Override
-    public @Nullable String getServicesSystemSharedLibraryPackageName() {
+    public @NonNull String getServicesSystemSharedLibraryPackageName() {
         try {
             return mPM.getServicesSystemSharedLibraryPackageName();
         } catch (RemoteException e) {
@@ -449,6 +449,17 @@
         }
     }
 
+    /**
+     * @hide
+     */
+    public @NonNull String getSharedSystemSharedLibraryPackageName() {
+        try {
+            return mPM.getSharedSystemSharedLibraryPackageName();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     @Override
     @SuppressWarnings("unchecked")
     public FeatureInfo[] getSystemAvailableFeatures() {
diff --git a/core/java/android/app/DialogFragment.java b/core/java/android/app/DialogFragment.java
index 9caf752..3198c7c 100644
--- a/core/java/android/app/DialogFragment.java
+++ b/core/java/android/app/DialogFragment.java
@@ -361,8 +361,8 @@
     }
 
     @Override
-    public void onAttach(Activity activity) {
-        super.onAttach(activity);
+    public void onAttach(Context context) {
+        super.onAttach(context);
         if (!mShownByMe) {
             // If not explicitly shown through our API, take this as an
             // indication that the dialog is no longer dismissed.
@@ -394,7 +394,6 @@
             mShowsDialog = savedInstanceState.getBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);
             mBackStackId = savedInstanceState.getInt(SAVED_BACK_STACK_ID, -1);
         }
-        
     }
 
     /** @hide */
@@ -473,11 +472,15 @@
         View view = getView();
         if (view != null) {
             if (view.getParent() != null) {
-                throw new IllegalStateException("DialogFragment can not be attached to a container view");
+                throw new IllegalStateException(
+                        "DialogFragment can not be attached to a container view");
             }
             mDialog.setContentView(view);
         }
-        mDialog.setOwnerActivity(getActivity());
+        final Activity activity = getActivity();
+        if (activity != null) {
+            mDialog.setOwnerActivity(activity);
+        }
         mDialog.setCancelable(mCancelable);
         if (!mDialog.takeCancelAndDismissListeners("DialogFragment", this, this)) {
             throw new IllegalStateException(
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index a221c98..f4fe1eb 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import android.animation.Animator;
+import android.annotation.CallSuper;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.StringRes;
@@ -1335,6 +1336,7 @@
      * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
      */
     @Deprecated
+    @CallSuper
     public void onInflate(AttributeSet attrs, Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1381,6 +1383,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onInflate(Context context, AttributeSet attrs, Bundle savedInstanceState) {
         onInflate(attrs, savedInstanceState);
         mCalled = true;
@@ -1421,6 +1424,7 @@
      * @deprecated Use {@link #onInflate(Context, AttributeSet, Bundle)} instead.
      */
     @Deprecated
+    @CallSuper
     public void onInflate(Activity activity, AttributeSet attrs, Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1429,6 +1433,7 @@
      * Called when a fragment is first attached to its context.
      * {@link #onCreate(Bundle)} will be called after this.
      */
+    @CallSuper
     public void onAttach(Context context) {
         mCalled = true;
         final Activity hostActivity = mHost == null ? null : mHost.getActivity();
@@ -1442,6 +1447,7 @@
      * @deprecated Use {@link #onAttach(Context)} instead.
      */
     @Deprecated
+    @CallSuper
     public void onAttach(Activity activity) {
         mCalled = true;
     }
@@ -1473,6 +1479,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onCreate(@Nullable Bundle savedInstanceState) {
         mCalled = true;
         final Context context = getContext();
@@ -1558,6 +1565,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onActivityCreated(@Nullable Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1573,6 +1581,7 @@
      * @param savedInstanceState If the fragment is being re-created from
      * a previous saved state, this is the state.
      */
+    @CallSuper
     public void onViewStateRestored(Bundle savedInstanceState) {
         mCalled = true;
     }
@@ -1582,6 +1591,7 @@
      * tied to {@link Activity#onStart() Activity.onStart} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onStart() {
         mCalled = true;
 
@@ -1603,6 +1613,7 @@
      * tied to {@link Activity#onResume() Activity.onResume} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onResume() {
         mCalled = true;
     }
@@ -1648,6 +1659,7 @@
     public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
     }
 
+    @CallSuper
     public void onConfigurationChanged(Configuration newConfig) {
         mCalled = true;
     }
@@ -1657,6 +1669,7 @@
      * tied to {@link Activity#onPause() Activity.onPause} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onPause() {
         mCalled = true;
     }
@@ -1666,14 +1679,17 @@
      * tied to {@link Activity#onStop() Activity.onStop} of the containing
      * Activity's lifecycle.
      */
+    @CallSuper
     public void onStop() {
         mCalled = true;
     }
 
+    @CallSuper
     public void onLowMemory() {
         mCalled = true;
     }
 
+    @CallSuper
     public void onTrimMemory(int level) {
         mCalled = true;
     }
@@ -1687,6 +1703,7 @@
      * non-null view.  Internally it is called after the view's state has
      * been saved but before it has been removed from its parent.
      */
+    @CallSuper
     public void onDestroyView() {
         mCalled = true;
     }
@@ -1695,6 +1712,7 @@
      * Called when the fragment is no longer in use.  This is called
      * after {@link #onStop()} and before {@link #onDetach()}.
      */
+    @CallSuper
     public void onDestroy() {
         mCalled = true;
         //Log.v("foo", "onDestroy: mCheckedForLoaderManager=" + mCheckedForLoaderManager
@@ -1743,20 +1761,9 @@
      * Activity re-creation (see {@link #setRetainInstance(boolean)}), in which case it is called
      * after {@link #onStop()}.
      */
+    @CallSuper
     public void onDetach() {
         mCalled = true;
-
-        // Destroy the child FragmentManager if we still have it here.
-        // We won't unless we're retaining our instance and if we do,
-        // our child FragmentManager instance state will have already been saved.
-        if (mChildFragmentManager != null) {
-            if (!mRetaining) {
-                throw new IllegalStateException("Child FragmentManager of " + this + " was not "
-                        + " destroyed and this fragment is not retaining instance");
-            }
-            mChildFragmentManager.dispatchDestroy();
-            mChildFragmentManager = null;
-        }
     }
 
     /**
@@ -2568,6 +2575,27 @@
         mChildFragmentManager = null;
     }
 
+    void performDetach() {
+        mCalled = false;
+        onDetach();
+        if (!mCalled) {
+            throw new SuperNotCalledException("Fragment " + this
+                    + " did not call through to super.onDetach()");
+        }
+
+        // Destroy the child FragmentManager if we still have it here.
+        // We won't unless we're retaining our instance and if we do,
+        // our child FragmentManager instance state will have already been saved.
+        if (mChildFragmentManager != null) {
+            if (!mRetaining) {
+                throw new IllegalStateException("Child FragmentManager of " + this + " was not "
+                        + " destroyed and this fragment is not retaining instance");
+            }
+            mChildFragmentManager.dispatchDestroy();
+            mChildFragmentManager = null;
+        }
+    }
+
     private static Transition loadTransition(Context context, TypedArray typedArray,
             Transition currentValue, Transition defaultValue, int id) {
         if (currentValue != defaultValue) {
diff --git a/core/java/android/app/FragmentManager.java b/core/java/android/app/FragmentManager.java
index b1dda7f..d795385 100644
--- a/core/java/android/app/FragmentManager.java
+++ b/core/java/android/app/FragmentManager.java
@@ -1117,12 +1117,7 @@
                                 f.mState = Fragment.INITIALIZING;
                             }
 
-                            f.mCalled = false;
-                            f.onDetach();
-                            if (!f.mCalled) {
-                                throw new SuperNotCalledException("Fragment " + f
-                                        + " did not call through to super.onDetach()");
-                            }
+                            f.performDetach();
                             if (!keepActive) {
                                 if (!f.mRetaining) {
                                     makeInactive(f);
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index b28b5e6..66b4fcf 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -649,6 +649,8 @@
 
     public void notifyLockedProfile(@UserIdInt int userId) throws RemoteException;
 
+    public void startConfirmDeviceCredentialIntent(Intent intent) throws RemoteException;
+
     /*
      * Private non-Binder interfaces
      */
@@ -1032,4 +1034,5 @@
     int IS_VR_PACKAGE_ENABLED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 371;
     int SWAP_DOCKED_AND_FULLSCREEN_STACK = IBinder.FIRST_CALL_TRANSACTION + 372;
     int NOTIFY_LOCKED_PROFILE = IBinder.FIRST_CALL_TRANSACTION + 373;
+    int START_CONFIRM_DEVICE_CREDENTIAL_INTENT = IBinder.FIRST_CALL_TRANSACTION + 374;
 }
diff --git a/core/java/android/app/IWallpaperManager.aidl b/core/java/android/app/IWallpaperManager.aidl
index 2fc6533..a42aed6 100644
--- a/core/java/android/app/IWallpaperManager.aidl
+++ b/core/java/android/app/IWallpaperManager.aidl
@@ -43,7 +43,8 @@
      * new wallpaper content is ready to display.
      */
     ParcelFileDescriptor setWallpaper(String name, in String callingPackage,
-            in Rect cropHint, out Bundle extras, int which, IWallpaperManagerCallback completion);
+            in Rect cropHint, boolean allowBackup, out Bundle extras, int which,
+            IWallpaperManagerCallback completion);
 
     /**
      * Set the live wallpaper. This only affects the system wallpaper.
@@ -125,6 +126,11 @@
     boolean isWallpaperSettingAllowed(in String callingPackage);
 
     /*
+     * Backup: is the current system wallpaper image eligible for off-device backup?
+     */
+    boolean isWallpaperBackupEligible(int userId);
+
+    /*
      * Keyguard: register a callback for being notified that lock-state relevant
      * wallpaper content has changed.
      */
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 4fca69a..95ea2a5 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1797,7 +1797,7 @@
         if (res >= ActivityManager.START_SUCCESS) {
             return;
         }
-        
+
         switch (res) {
             case ActivityManager.START_INTENT_NOT_RESOLVED:
             case ActivityManager.START_CLASS_NOT_FOUND:
@@ -1820,6 +1820,15 @@
             case ActivityManager.START_NOT_VOICE_COMPATIBLE:
                 throw new SecurityException(
                         "Starting under voice control not allowed for: " + intent);
+            case ActivityManager.START_VOICE_NOT_ACTIVE_SESSION:
+                throw new IllegalStateException(
+                        "Session calling startVoiceActivity does not match active session");
+            case ActivityManager.START_VOICE_HIDDEN_SESSION:
+                throw new IllegalStateException(
+                        "Cannot start voice activity on a hidden session");
+            case ActivityManager.START_CANCELED:
+                throw new AndroidRuntimeException("Activity could not be started for "
+                        + intent);
             default:
                 throw new AndroidRuntimeException("Unknown error code "
                         + res + " when starting " + intent);
diff --git a/core/java/android/app/ListFragment.java b/core/java/android/app/ListFragment.java
index dc8420e..0b96d84 100644
--- a/core/java/android/app/ListFragment.java
+++ b/core/java/android/app/ListFragment.java
@@ -274,7 +274,7 @@
     }
 
     /**
-     * Get the activity's list view widget.
+     * Get the fragment's list view widget.
      */
     public ListView getListView() {
         ensureList();
@@ -346,9 +346,9 @@
         if (shown) {
             if (animate) {
                 mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
-                        getActivity(), android.R.anim.fade_out));
+                        getContext(), android.R.anim.fade_out));
                 mListContainer.startAnimation(AnimationUtils.loadAnimation(
-                        getActivity(), android.R.anim.fade_in));
+                        getContext(), android.R.anim.fade_in));
             } else {
                 mProgressContainer.clearAnimation();
                 mListContainer.clearAnimation();
@@ -358,9 +358,9 @@
         } else {
             if (animate) {
                 mProgressContainer.startAnimation(AnimationUtils.loadAnimation(
-                        getActivity(), android.R.anim.fade_in));
+                        getContext(), android.R.anim.fade_in));
                 mListContainer.startAnimation(AnimationUtils.loadAnimation(
-                        getActivity(), android.R.anim.fade_out));
+                        getContext(), android.R.anim.fade_out));
             } else {
                 mProgressContainer.clearAnimation();
                 mListContainer.clearAnimation();
@@ -371,7 +371,7 @@
     }
     
     /**
-     * Get the ListAdapter associated with this activity's ListView.
+     * Get the ListAdapter associated with this fragment's ListView.
      */
     public ListAdapter getListAdapter() {
         return mAdapter;
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index 849636f..0cfa009 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -432,7 +432,8 @@
         if (!Objects.equals(mPackageName, ActivityThread.currentPackageName())) {
             VMRuntime.getRuntime().vmInstructionSet();
             try {
-                ActivityThread.getPackageManager().notifyPackageUse(mPackageName);
+                ActivityThread.getPackageManager().notifyPackageUse(mPackageName,
+                        PackageManager.NOTIFY_PACKAGE_USE_CROSS_PACKAGE);
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 400a313..43c6ca5 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -25,7 +25,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.ColorStateList;
@@ -186,6 +185,11 @@
     public long when;
 
     /**
+     * The creation time of the notification
+     */
+    private long creationTime;
+
+    /**
      * The resource id of a drawable to use as the icon in the status bar.
      *
      * @deprecated Use {@link Builder#setSmallIcon(Icon)} instead.
@@ -943,10 +947,10 @@
     public static final String EXTRA_ALLOW_GENERATED_REPLIES = "android.allowGeneratedReplies";
 
     /**
-     * {@link #extras} key: a {@link String} to be displayed as the title to a thread represented by
-     * a {@link android.app.Notification.MessagingStyle}
+     * {@link #extras} key: a {@link String} to be displayed as the title to a conversation
+     * represented by a {@link android.app.Notification.MessagingStyle}
      */
-    public static final String EXTRA_THREAD_TITLE = "android.threadTitle";
+    public static final String EXTRA_CONVERSATION_TITLE = "android.conversationTitle";
 
     /**
      * {@link #extras} key: an array of {@link android.app.Notification.MessagingStyle.Message}
@@ -1480,6 +1484,7 @@
     public Notification()
     {
         this.when = System.currentTimeMillis();
+        this.creationTime = System.currentTimeMillis();
         this.priority = PRIORITY_DEFAULT;
     }
 
@@ -1517,6 +1522,7 @@
         this.icon = icon;
         this.tickerText = tickerText;
         this.when = when;
+        this.creationTime = System.currentTimeMillis();
     }
 
     /**
@@ -1527,6 +1533,7 @@
         int version = parcel.readInt();
 
         when = parcel.readLong();
+        creationTime = parcel.readLong();
         if (parcel.readInt() != 0) {
             mSmallIcon = Icon.CREATOR.createFromParcel(parcel);
             if (mSmallIcon.getType() == Icon.TYPE_RESOURCE) {
@@ -1615,6 +1622,7 @@
      */
     public void cloneInto(Notification that, boolean heavy) {
         that.when = this.when;
+        that.creationTime = this.creationTime;
         that.mSmallIcon = this.mSmallIcon;
         that.number = this.number;
 
@@ -1795,6 +1803,7 @@
         parcel.writeInt(1);
 
         parcel.writeLong(when);
+        parcel.writeLong(creationTime);
         if (mSmallIcon == null && icon != 0) {
             // you snuck an icon in here without using the builder; let's try to keep it
             mSmallIcon = Icon.createWithResource("", icon);
@@ -3130,6 +3139,7 @@
             contentView.setViewVisibility(R.id.header_text, View.GONE);
             contentView.setViewVisibility(R.id.header_text_divider, View.GONE);
             contentView.setViewVisibility(R.id.time_divider, View.GONE);
+            contentView.setViewVisibility(R.id.time, View.GONE);
             contentView.setImageViewIcon(R.id.profile_badge, null);
             contentView.setViewVisibility(R.id.profile_badge, View.GONE);
         }
@@ -3260,11 +3270,15 @@
                             mN.when + (SystemClock.elapsedRealtime() - System.currentTimeMillis()));
                     contentView.setBoolean(R.id.chronometer, "setStarted", true);
                     boolean countsDown = mN.extras.getBoolean(EXTRA_CHRONOMETER_COUNTS_DOWN);
-                    contentView.setChronometerCountsDown(R.id.chronometer, countsDown);
+                    contentView.setChronometerCountDown(R.id.chronometer, countsDown);
                 } else {
                     contentView.setViewVisibility(R.id.time, View.VISIBLE);
                     contentView.setLong(R.id.time, "setTime", mN.when);
                 }
+            } else {
+                // We still want a time to be set but gone, such that we can show and hide it
+                // on demand in case it's a child notification without anything in the header
+                contentView.setLong(R.id.time, "setTime", mN.when != 0 ? mN.when : mN.creationTime);
             }
         }
 
@@ -3332,7 +3346,7 @@
          *         otherwise
          */
         private boolean showsTimeOrChronometer() {
-            return mN.when != 0 && mN.extras.getBoolean(EXTRA_SHOW_WHEN);
+            return mN.showsTimeOrChronometer();
         }
 
         private void resetStandardTemplateWithActions(RemoteViews big) {
@@ -3694,6 +3708,8 @@
                 mN.extras = getAllExtras();
             }
 
+            mN.creationTime = System.currentTimeMillis();
+
             // lazy stuff from mContext; see comment in Builder(Context, Notification)
             Notification.addFieldsFromContext(mContext, mN);
 
@@ -3827,6 +3843,15 @@
     }
 
     /**
+     * @return true if the notification will show the time or the chronometer; false
+     *         otherwise
+     * @hide
+     */
+    public boolean showsTimeOrChronometer() {
+        return when != 0 && extras.getBoolean(EXTRA_SHOW_WHEN);
+    }
+
+    /**
      * An object that can apply a rich notification style to a {@link Notification.Builder}
      * object.
      */
@@ -4301,7 +4326,7 @@
         CharSequence mUserDisplayName;
         CharSequence mConversationTitle;
         boolean mAllowGeneratedReplies = true;
-        ArrayList<Message> mMessages = new ArrayList<>();
+        List<Message> mMessages = new ArrayList<>();
 
         MessagingStyle() {
         }
@@ -4414,11 +4439,11 @@
                 extras.putCharSequence(EXTRA_SELF_DISPLAY_NAME, mUserDisplayName);
             }
             if (mConversationTitle != null) {
-                extras.putCharSequence(EXTRA_THREAD_TITLE, mConversationTitle);
+                extras.putCharSequence(EXTRA_CONVERSATION_TITLE, mConversationTitle);
             }
             extras.putBoolean(EXTRA_ALLOW_GENERATED_REPLIES, mAllowGeneratedReplies);
-            if (!mMessages.isEmpty()) {
-                extras.putParcelableArrayList(EXTRA_MESSAGES, mMessages);
+            if (!mMessages.isEmpty()) { extras.putParcelableArray(EXTRA_MESSAGES,
+                    Message.getBundleArrayForMessages(mMessages));
             }
         }
 
@@ -4431,12 +4456,12 @@
 
             mMessages.clear();
             mUserDisplayName = extras.getString(EXTRA_SELF_DISPLAY_NAME);
-            mConversationTitle = extras.getString(EXTRA_THREAD_TITLE);
+            mConversationTitle = extras.getString(EXTRA_CONVERSATION_TITLE);
             mAllowGeneratedReplies = extras.getBoolean(EXTRA_ALLOW_GENERATED_REPLIES,
                     mAllowGeneratedReplies);
-            List<Message> messages = extras.getParcelableArrayList(EXTRA_MESSAGES);
-            if (messages != null) {
-                mMessages.addAll(messages);
+            Parcelable[] parcelables = extras.getParcelableArray(EXTRA_MESSAGES);
+            if (parcelables != null && parcelables instanceof Bundle[]) {
+                mMessages = Message.getMessagesFromBundleArray((Bundle[]) parcelables);
             }
         }
 
@@ -4537,7 +4562,13 @@
                     ColorStateList.valueOf(color), null);
         }
 
-        public static final class Message implements Parcelable {
+        public static final class Message {
+
+            static final String KEY_TEXT = "text";
+            static final String KEY_TIMESTAMP = "time";
+            static final String KEY_SENDER = "sender";
+            static final String KEY_DATA_MIME_TYPE = "type";
+            static final String KEY_DATA_URI= "uri";
 
             private final CharSequence mText;
             private final long mTimestamp;
@@ -4595,26 +4626,6 @@
                 return this;
             }
 
-            private Message(Parcel in) {
-                if (in.readInt() != 0) {
-                    mText = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-                } else {
-                    mText = null;
-                }
-                mTimestamp = in.readLong();
-                if (in.readInt() != 0) {
-                    mSender = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
-                } else {
-                    mSender = null;
-                }
-                if (in.readInt() != 0) {
-                    mDataMimeType = in.readString();
-                }
-                if (in.readInt() != 0) {
-                    mDataUri = in.readParcelable(Uri.class.getClassLoader());
-                }
-            }
-
             /**
              * Get the text to be used for this message, or the fallback text if a type and content
              * Uri have been set
@@ -4652,49 +4663,64 @@
                 return mDataUri;
             }
 
-            @Override
-            public int describeContents() {
-                return 0;
-            }
-
-            @Override
-            public void writeToParcel(Parcel out, int flags) {
+            private Bundle toBundle() {
+                Bundle bundle = new Bundle();
                 if (mText != null) {
-                    out.writeInt(1);
-                    TextUtils.writeToParcel(mText, out, flags);
-                } else {
-                    out.writeInt(0);
+                    bundle.putCharSequence(KEY_TEXT, mText);
                 }
-                out.writeLong(mTimestamp);
+                bundle.putLong(KEY_TIMESTAMP, mTimestamp);
                 if (mSender != null) {
-                    out.writeInt(1);
-                    TextUtils.writeToParcel(mSender, out, flags);
-                } else {
-                    out.writeInt(0);
+                    bundle.putCharSequence(KEY_SENDER, mSender);
                 }
                 if (mDataMimeType != null) {
-                    out.writeInt(1);
-                    out.writeString(mDataMimeType);
-                } else {
-                    out.writeInt(0);
+                    bundle.putString(KEY_DATA_MIME_TYPE, mDataMimeType);
                 }
                 if (mDataUri != null) {
-                    out.writeInt(1);
-                    out.writeParcelable(mDataUri, flags);
-                } else {
-                    out.writeInt(0);
+                    bundle.putParcelable(KEY_DATA_URI, mDataUri);
                 }
+                return bundle;
             }
 
-            public static final Parcelable.Creator<Message> CREATOR =
-                    new Parcelable.Creator<Message>() {
-                        public Message createFromParcel(Parcel in) {
-                            return new Message(in);
+            static Bundle[] getBundleArrayForMessages(List<Message> messages) {
+                Bundle[] bundles = new Bundle[messages.size()];
+                final int N = messages.size();
+                for (int i = 0; i < N; i++) {
+                    bundles[i] = messages.get(i).toBundle();
+                }
+                return bundles;
+            }
+
+            static List<Message> getMessagesFromBundleArray(Bundle[] bundles) {
+                List<Message> messages = new ArrayList<>(bundles.length);
+                for (int i = 0; i < bundles.length; i++) {
+                    Message message = getMessageFromBundle(bundles[i]);
+                    if (message != null) {
+                        messages.add(message);
+                    }
+                }
+                return messages;
+            }
+
+            static Message getMessageFromBundle(Bundle bundle) {
+                try {
+                    if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP) ||
+                            !bundle.containsKey(KEY_SENDER)) {
+                        return null;
+                    } else {
+                        Message message = new Message(bundle.getCharSequence(KEY_TEXT),
+                                bundle.getLong(KEY_TIMESTAMP), bundle.getCharSequence(KEY_SENDER));
+                        if (bundle.containsKey(KEY_DATA_MIME_TYPE) &&
+                                bundle.containsKey(KEY_DATA_URI)) {
+
+                            message.setData(bundle.getString(KEY_DATA_MIME_TYPE),
+                                    (Uri) bundle.getParcelable(KEY_DATA_URI));
                         }
-                        public Message[] newArray(int size) {
-                            return new Message[size];
-                        }
-                    };
+                        return message;
+                    }
+                } catch (ClassCastException e) {
+                    return null;
+                }
+            }
         }
     }
 
@@ -5436,6 +5462,7 @@
         private static final int FLAG_HINT_SHOW_BACKGROUND_ONLY = 1 << 2;
         private static final int FLAG_START_SCROLL_BOTTOM = 1 << 3;
         private static final int FLAG_HINT_AVOID_BACKGROUND_CLIPPING = 1 << 4;
+        private static final int FLAG_BIG_PICTURE_AMBIENT = 1 << 5;
         private static final int FLAG_HINT_CONTENT_INTENT_LAUNCHES_ACTIVITY = 1 << 6;
 
         // Default value for flags integer
@@ -6004,6 +6031,29 @@
         }
 
         /**
+         * Set a hint that this notification's {@link BigPictureStyle} (if present) should be
+         * converted to low-bit and displayed in ambient mode, especially useful for barcodes and
+         * qr codes, as well as other simple black-and-white tickets.
+         * @param hintAmbientBigPicture {@code true} to enable converstion and ambient.
+         * @return this object for method chaining
+         */
+        public WearableExtender setHintAmbientBigPicture(boolean hintAmbientBigPicture) {
+            setFlag(FLAG_BIG_PICTURE_AMBIENT, hintAmbientBigPicture);
+            return this;
+        }
+
+        /**
+         * Get a hint that this notification's {@link BigPictureStyle} (if present) should be
+         * converted to low-bit and displayed in ambient mode, especially useful for barcodes and
+         * qr codes, as well as other simple black-and-white tickets.
+         * @return {@code true} if it should be displayed in ambient, false otherwise
+         * otherwise. The default value is {@code false} if this was never set.
+         */
+        public boolean getHintAmbientBigPicture() {
+            return (mFlags & FLAG_BIG_PICTURE_AMBIENT) != 0;
+        }
+
+        /**
          * Set a hint that this notification's content intent will launch an {@link Activity}
          * directly, telling the platform that it can generate the appropriate transitions.
          * @param hintContentIntentLaunchesActivity {@code true} if the content intent will launch
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index aef92cf..d8a3d4f 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -224,7 +224,7 @@
      * @return a new AssetManager.
     */
     @VisibleForTesting
-    protected AssetManager createAssetManager(@NonNull final ResourcesKey key) {
+    protected @NonNull AssetManager createAssetManager(@NonNull final ResourcesKey key) {
         AssetManager assets = new AssetManager();
 
         // resDir can be null if the 'android' package is creating a new Resources object.
@@ -232,14 +232,15 @@
         // already.
         if (key.mResDir != null) {
             if (assets.addAssetPath(key.mResDir) == 0) {
-                return null;
+                throw new IllegalArgumentException("failed to add asset path " + key.mResDir);
             }
         }
 
         if (key.mSplitResDirs != null) {
             for (final String splitResDir : key.mSplitResDirs) {
                 if (assets.addAssetPath(splitResDir) == 0) {
-                    return null;
+                    throw new IllegalArgumentException(
+                            "failed to add split asset path " + splitResDir);
                 }
             }
         }
diff --git a/core/java/android/app/WallpaperManager.java b/core/java/android/app/WallpaperManager.java
index 72b9318..18a5593 100644
--- a/core/java/android/app/WallpaperManager.java
+++ b/core/java/android/app/WallpaperManager.java
@@ -1,5 +1,5 @@
 /*
-h * Copyright (C) 2009 The Android Open Source Project
+ * Copyright (C) 2009 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.
@@ -875,7 +875,7 @@
             /* Set the wallpaper to the default values */
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(
                     "res:" + resources.getResourceName(resid),
-                    mContext.getOpPackageName(), null, result, which, completion);
+                    mContext.getOpPackageName(), null, false, result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 boolean ok = false;
@@ -985,7 +985,8 @@
         final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
+                    result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1102,7 +1103,8 @@
         final WallpaperSetCompletion completion = new WallpaperSetCompletion();
         try {
             ParcelFileDescriptor fd = sGlobals.mService.setWallpaper(null,
-                    mContext.getOpPackageName(), visibleCropHint, result, which, completion);
+                    mContext.getOpPackageName(), visibleCropHint, allowBackup,
+                    result, which, completion);
             if (fd != null) {
                 FileOutputStream fos = null;
                 try {
@@ -1565,6 +1567,25 @@
         }
     }
 
+    /**
+     * Is the current system wallpaper eligible for backup?
+     *
+     * Only the OS itself may use this method.
+     * @hide
+     */
+    public boolean isWallpaperBackupEligible() {
+        if (sGlobals.mService == null) {
+            Log.w(TAG, "WallpaperService not running");
+            return false;
+        }
+        try {
+            return sGlobals.mService.isWallpaperBackupEligible(mContext.getUserId());
+        } catch (RemoteException e) {
+            Log.e(TAG, "Exception querying wallpaper backup eligibility: " + e.getMessage());
+        }
+        return false;
+    }
+
     // Private completion callback for setWallpaper() synchronization
     private class WallpaperSetCompletion extends IWallpaperManagerCallback.Stub {
         final CountDownLatch mLatch;
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index c84a0dc..602d950 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -24,7 +24,7 @@
 import android.os.Parcelable;
 import android.os.PersistableBundle;
 import android.util.Log;
-import static android.util.TimeUtils.formatForLogging;
+import static android.util.TimeUtils.formatDuration;
 
 import java.util.ArrayList;
 
@@ -760,15 +760,27 @@
                         " setRequiresDeviceIdle is an error.");
             }
             JobInfo job = new JobInfo(this);
-            if (job.intervalMillis != job.getIntervalMillis()) {
-                Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
-                        + formatForLogging(mIntervalMillis) + ". Clamped to " +
-                        formatForLogging(job.getIntervalMillis()));
-            }
-            if (job.flexMillis != job.getFlexMillis()) {
-                Log.w(TAG, "Specified interval for " + mJobService.getPackageName() + " is "
-                        + formatForLogging(mFlexMillis) + ". Clamped to " +
-                        formatForLogging(job.getFlexMillis()));
+            if (job.isPeriodic()) {
+                if (job.intervalMillis != job.getIntervalMillis()) {
+                    StringBuilder builder = new StringBuilder();
+                    builder.append("Specified interval for ")
+                            .append(String.valueOf(mJobId))
+                            .append(" is ");
+                    formatDuration(mIntervalMillis, builder);
+                    builder.append(". Clamped to ");
+                    formatDuration(job.getIntervalMillis(), builder);
+                    Log.w(TAG, builder.toString());
+                }
+                if (job.flexMillis != job.getFlexMillis()) {
+                    StringBuilder builder = new StringBuilder();
+                    builder.append("Specified flex for ")
+                            .append(String.valueOf(mJobId))
+                            .append(" is ");
+                    formatDuration(mFlexMillis, builder);
+                    builder.append(". Clamped to ");
+                    formatDuration(job.getFlexMillis(), builder);
+                    Log.w(TAG, builder.toString());
+                }
             }
             return job;
         }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 996ccba..47abd2b 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1427,6 +1427,16 @@
             "android.intent.action.SHOW_KEYBOARD_SHORTCUTS";
 
     /**
+     * Activity Action: Dismiss the Keyboard Shortcuts Helper screen.
+     * <p>Input: Nothing.
+     * <p>Output: Nothing.
+     * @hide
+     */
+    @SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
+    public static final String ACTION_DISMISS_KEYBOARD_SHORTCUTS =
+            "android.intent.action.DISMISS_KEYBOARD_SHORTCUTS";
+
+    /**
      * Activity Action: Show settings for managing network data usage of a
      * specific application. Applications should define an activity that offers
      * options to control data usage.
@@ -1551,6 +1561,7 @@
      * {@link} #ACTION_VIEW} to indicate the uid of the package that initiated the install
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_ORIGINATING_UID
             = "android.intent.extra.ORIGINATING_UID";
 
@@ -1624,6 +1635,7 @@
      *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MANAGE_APP_PERMISSIONS =
             "android.intent.action.MANAGE_APP_PERMISSIONS";
@@ -1639,6 +1651,7 @@
      *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MANAGE_PERMISSIONS =
             "android.intent.action.MANAGE_PERMISSIONS";
@@ -1676,6 +1689,7 @@
      *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_REVIEW_PERMISSIONS =
             "android.intent.action.REVIEW_PERMISSIONS";
@@ -1688,6 +1702,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_REMOTE_CALLBACK = "android.intent.extra.REMOTE_CALLBACK";
 
     /**
@@ -1707,102 +1722,10 @@
      *
      * @hide
      */
+    @SystemApi
     public static final String EXTRA_RESULT_NEEDED = "android.intent.extra.RESULT_NEEDED";
 
     /**
-     * Broadcast action that requests current permission granted information.  It will respond
-     * to the request by sending a broadcast with action defined by
-     * {@link #EXTRA_GET_PERMISSIONS_RESPONSE_INTENT}. The response will contain
-     * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}, as well as
-     * {@link #EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT}, with contents described below or
-     * a null upon failure.
-     *
-     * <p>If {@link #EXTRA_PACKAGE_NAME} is included then the number of permissions granted, the
-     * number of permissions requested and the number of granted additional permissions
-     * by that package will be calculated and included as the first
-     * and second elements respectively of an int[] in the response as
-     * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}.  The response will also deliver the list
-     * of localized permission group names that are granted in
-     * {@link #EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT}.
-     *
-     * <p>If {@link #EXTRA_PACKAGE_NAME} is not included then the number of apps granted any runtime
-     * permissions and the total number of apps requesting runtime permissions will be the first
-     * and second elements respectively of an int[] in the response as
-     * {@link #EXTRA_GET_PERMISSIONS_COUNT_RESULT}.
-     *
-     * @hide
-     */
-    public static final String ACTION_GET_PERMISSIONS_COUNT
-            = "android.intent.action.GET_PERMISSIONS_COUNT";
-
-    /**
-     * Broadcast action that requests list of all apps that have runtime permissions.  It will
-     * respond to the request by sending a broadcast with action defined by
-     * {@link #EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT}. The response will contain
-     * {@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT}, as well as
-     * {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}, with contents described below or
-     * a null upon failure.
-     *
-     * <p>{@link #EXTRA_GET_PERMISSIONS_APP_LIST_RESULT} will contain a list of package names of
-     * apps that have runtime permissions. {@link #EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT}
-     * will contain the list of app labels corresponding ot the apps in the first list.
-     *
-     * @hide
-     */
-    public static final String ACTION_GET_PERMISSIONS_PACKAGES
-            = "android.intent.action.GET_PERMISSIONS_PACKAGES";
-
-    /**
-     * Extra included in response to {@link #ACTION_GET_PERMISSIONS_COUNT}.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_COUNT_RESULT
-            = "android.intent.extra.GET_PERMISSIONS_COUNT_RESULT";
-
-    /**
-     * List of CharSequence of localized permission group labels.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_GROUP_LIST_RESULT
-            = "android.intent.extra.GET_PERMISSIONS_GROUP_LIST_RESULT";
-
-    /**
-     * String list of apps that have one or more runtime permissions.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_APP_LIST_RESULT
-            = "android.intent.extra.GET_PERMISSIONS_APP_LIST_RESULT";
-
-    /**
-     * String list of app labels for apps that have one or more runtime permissions.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_APP_LABEL_LIST_RESULT
-            = "android.intent.extra.GET_PERMISSIONS_APP_LABEL_LIST_RESULT";
-
-    /**
-     * Boolean list describing if the app is a system app for apps that have one or more runtime
-     * permissions.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT
-            = "android.intent.extra.GET_PERMISSIONS_IS_SYSTEM_APP_LIST_RESULT";
-
-    /**
-     * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_COUNT} broadcasts.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_RESPONSE_INTENT
-            = "android.intent.extra.GET_PERMISSIONS_RESONSE_INTENT";
-
-    /**
-     * Required extra to be sent with {@link #ACTION_GET_PERMISSIONS_PACKAGES} broadcasts.
-     * @hide
-     */
-    public static final String EXTRA_GET_PERMISSIONS_PACKAGES_RESPONSE_INTENT
-            = "android.intent.extra.GET_PERMISSIONS_PACKAGES_RESONSE_INTENT";
-
-    /**
      * Activity action: Launch UI to manage which apps have a given permission.
      * <p>
      * Input: {@link #EXTRA_PERMISSION_NAME} specifies the permission access
@@ -1816,6 +1739,7 @@
      *
      * @hide
      */
+    @SystemApi
     @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
     public static final String ACTION_MANAGE_PERMISSION_APPS =
             "android.intent.action.MANAGE_PERMISSION_APPS";
@@ -3078,10 +3002,6 @@
     public static final String ACTION_MANAGED_PROFILE_UNLOCKED =
             "android.intent.action.MANAGED_PROFILE_UNLOCKED";
 
-    /** @hide */
-    public static final String ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED =
-            "android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED";
-
     /**
      * Broadcast sent to the primary user when an associated managed profile has become available.
      * Currently this includes when the user disables quiet mode for the profile. Carries an extra
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 0526815..0c79312 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -451,9 +451,11 @@
     void updatePackagesIfNeeded();
 
     /**
-     * Notify the package manager that a package is going to be used.
+     * Notify the package manager that a package is going to be used and why.
+     *
+     * See PackageManager.NOTIFY_PACKAGE_USE_* for reasons.
      */
-    void notifyPackageUse(String packageName);
+    void notifyPackageUse(String packageName, int reason);
 
     /**
      * Ask the package manager to perform dex-opt (if needed) on the given
@@ -565,6 +567,7 @@
     boolean setRequiredForSystemUser(String packageName, boolean systemUserApp);
 
     String getServicesSystemSharedLibraryPackageName();
+    String getSharedSystemSharedLibraryPackageName();
 
     boolean isPackageDeviceAdminOnAnyUser(String packageName);
 
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 496bae4..b04cbc5 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -2367,6 +2367,7 @@
     *
     * @hide
     */
+    @SystemApi
     public static final int FLAG_PERMISSION_USER_SET = 1 << 0;
 
     /**
@@ -2376,6 +2377,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int FLAG_PERMISSION_USER_FIXED =  1 << 1;
 
     /**
@@ -2385,6 +2387,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int FLAG_PERMISSION_POLICY_FIXED =  1 << 2;
 
     /**
@@ -2397,6 +2400,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE =  1 << 3;
 
     /**
@@ -2405,6 +2409,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int FLAG_PERMISSION_SYSTEM_FIXED =  1 << 4;
 
     /**
@@ -2415,6 +2420,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT =  1 << 5;
 
     /**
@@ -2423,6 +2429,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final int FLAG_PERMISSION_REVIEW_REQUIRED =  1 << 6;
 
     /**
@@ -2456,6 +2463,69 @@
     public static final String SYSTEM_SHARED_LIBRARY_SHARED = "android.ext.shared";
 
     /**
+     * Used when starting a process for an Activity.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_ACTIVITY = 0;
+
+    /**
+     * Used when starting a process for a Service.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_SERVICE = 1;
+
+    /**
+     * Used when moving a Service to the foreground.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE = 2;
+
+    /**
+     * Used when starting a process for a BroadcastReceiver.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER = 3;
+
+    /**
+     * Used when starting a process for a ContentProvider.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_CONTENT_PROVIDER = 4;
+
+    /**
+     * Used when starting a process for a BroadcastReceiver.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_BACKUP = 5;
+
+    /**
+     * Used with Context.getClassLoader() across Android packages.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_CROSS_PACKAGE = 6;
+
+    /**
+     * Used when starting a package within a process for Instrumentation.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_INSTRUMENTATION = 7;
+
+    /**
+     * Total number of usage reasons.
+     *
+     * @hide
+     */
+    public static final int NOTIFY_PACKAGE_USE_REASONS_COUNT = 8;
+
+    /**
      * Retrieve overall information about an application package that is
      * installed on the system.
      *
@@ -3061,6 +3131,7 @@
      *
      * @hide
      */
+    @SystemApi
     public abstract List<PackageInfo> getInstalledPackagesAsUser(@PackageInfoFlags int flags,
             @UserIdInt int userId);
 
@@ -3510,7 +3581,16 @@
      *
      * @hide
      */
-    public abstract @Nullable String getServicesSystemSharedLibraryPackageName();
+    public abstract @NonNull String getServicesSystemSharedLibraryPackageName();
+
+    /**
+     * Get the name of the package hosting the shared components shared library.
+     *
+     * @return The library host package.
+     *
+     * @hide
+     */
+    public abstract @NonNull String getSharedSystemSharedLibraryPackageName();
 
     /**
      * Get a list of features that are available on the
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index bb8bca4..4613800 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -4756,7 +4756,8 @@
         public int mPreferredOrder = 0;
 
         // For use by package manager to keep track of when a package was last used.
-        public long mLastPackageUsageTimeInMills;
+        public long[] mLastPackageUsageTimeInMills =
+                new long[PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT];
 
         // // User set enabled state.
         // public int mSetEnabled = PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;
@@ -5086,6 +5087,14 @@
             return true;
         }
 
+        public long getLatestPackageUseTimeInMills() {
+            long latestUse = 0L;
+            for (long use : mLastPackageUsageTimeInMills) {
+                latestUse = Math.max(latestUse, use);
+            }
+            return latestUse;
+        }
+
         public String toString() {
             return "Package{"
                 + Integer.toHexString(System.identityHashCode(this))
diff --git a/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
new file mode 100644
index 0000000..8766508
--- /dev/null
+++ b/core/java/android/content/pm/permission/IRuntimePermissionPresenter.aidl
@@ -0,0 +1,29 @@
+/*
+ * 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.content.pm.permission;
+
+import android.os.RemoteCallback;
+
+/**
+ * Interface for communication with the permission presenter service.
+ *
+ * @hide
+ */
+oneway interface IRuntimePermissionPresenter {
+    void getAppPermissions(String packageName, in RemoteCallback callback);
+    void getAppsUsingPermissions(boolean system, in RemoteCallback callback);
+}
\ No newline at end of file
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.aidl b/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.aidl
new file mode 100644
index 0000000..f96a32f
--- /dev/null
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.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 android.content.pm.permission;
+
+parcelable RuntimePermissionPresentationInfo;
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java b/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java
new file mode 100644
index 0000000..352e8ad
--- /dev/null
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresentationInfo.java
@@ -0,0 +1,110 @@
+/*
+ * 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.content.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * This class contains information about how a runtime permission
+ * is to be presented in the UI. A single runtime permission
+ * presented to the user may correspond to multiple platform defined
+ * permissions, e.g. the location permission may control both the
+ * coarse and fine platform permissions.
+ *
+ * @hide
+ */
+@SystemApi
+public final class RuntimePermissionPresentationInfo implements Parcelable {
+    private static final int FLAG_GRANTED = 1 << 0;
+    private static final int FLAG_STANDARD = 1 << 1;
+
+    private final CharSequence mLabel;
+    private final int mFlags;
+
+    /**
+     * Creates a new instance.
+     *
+     * @param label The permission label.
+     * @param granted Whether the permission is granted.
+     * @param standard Whether this is a platform-defined permission.
+     */
+    public RuntimePermissionPresentationInfo(CharSequence label,
+            boolean granted, boolean standard) {
+        mLabel = label;
+        int flags = 0;
+        if (granted) {
+            flags |= FLAG_GRANTED;
+        }
+        if (standard) {
+            flags |= FLAG_STANDARD;
+        }
+        mFlags = flags;
+    }
+
+    private RuntimePermissionPresentationInfo(Parcel parcel) {
+        mLabel = parcel.readCharSequence();
+        mFlags = parcel.readInt();
+    }
+
+    /**
+     * @return Whether the permission is granted.
+     */
+    public boolean isGranted() {
+        return (mFlags & FLAG_GRANTED) != 0;
+    }
+
+    /**
+     * @return Whether the permission is platform-defined.
+     */
+    public boolean isStandard() {
+        return (mFlags & FLAG_STANDARD) != 0;
+    }
+
+    /**
+     * Gets the permission label.
+     *
+     * @return The label.
+     */
+    public @NonNull CharSequence getLabel() {
+        return mLabel;
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    public void writeToParcel(Parcel parcel, int flags) {
+        parcel.writeCharSequence(mLabel);
+        parcel.writeInt(mFlags);
+    }
+
+    public static final Creator<RuntimePermissionPresentationInfo> CREATOR =
+            new Creator<RuntimePermissionPresentationInfo>() {
+        public RuntimePermissionPresentationInfo createFromParcel(Parcel source) {
+            return new RuntimePermissionPresentationInfo(source);
+        }
+
+        public RuntimePermissionPresentationInfo[] newArray(int size) {
+            return new RuntimePermissionPresentationInfo[size];
+        }
+    };
+}
diff --git a/core/java/android/content/pm/permission/RuntimePermissionPresenter.java b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
new file mode 100644
index 0000000..2e39926
--- /dev/null
+++ b/core/java/android/content/pm/permission/RuntimePermissionPresenter.java
@@ -0,0 +1,330 @@
+/*
+ * 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.content.pm.permission;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.content.pm.ApplicationInfo;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Message;
+import android.os.RemoteCallback;
+import android.os.RemoteException;
+import android.permissionpresenterservice.RuntimePermissionPresenterService;
+import android.util.Log;
+import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.SomeArgs;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * This class provides information about runtime permissions for a specific
+ * app or all apps. This information is dedicated for presentation purposes
+ * and does not necessarily reflect the individual permissions requested/
+ * granted to an app as the platform may be grouping permissions to improve
+ * presentation and help the user make an informed choice. For example, all
+ * runtime permissions in the same permission group may be presented as a
+ * single permission in the UI.
+ *
+ * @hide
+ */
+public final class RuntimePermissionPresenter {
+    private static final String TAG = "RuntimePermPresenter";
+
+    /**
+     * The key for retrieving the result from the returned bundle.
+     *
+     * @hide
+     */
+    public static final String KEY_RESULT =
+            "android.content.pm.permission.RuntimePermissionPresenter.key.result";
+
+    /**
+     * Listener for delivering a result.
+     */
+    public static abstract class OnResultCallback {
+        /**
+         * The result for {@link #getAppPermissions(String, OnResultCallback, Handler)}.
+         * @param permissions The permissions list.
+         */
+        public void onGetAppPermissions(@NonNull
+                List<RuntimePermissionPresentationInfo> permissions) {
+            /* do nothing - stub */
+        }
+
+        /**
+         * The result for {@link #getAppsUsingPermissions(boolean, List)}.
+         * @param system Whether to return only the system apps or only the non-system ones.
+         * @param apps The apps using runtime permissions.
+         */
+        public void getAppsUsingPermissions(boolean system, @NonNull List<ApplicationInfo> apps) {
+            /* do nothing - stub */
+        }
+    }
+
+    private static final Object sLock = new Object();
+
+    @GuardedBy("sLock")
+    private static RuntimePermissionPresenter sInstance;
+
+    private final RemoteService mRemoteService;
+
+    /**
+     * Gets the singleton runtime permission presenter.
+     *
+     * @param context Context for accessing resources.
+     * @return The singleton instance.
+     */
+    public static RuntimePermissionPresenter getInstance(@NonNull Context context) {
+        synchronized (sLock) {
+            if (sInstance == null) {
+                sInstance = new RuntimePermissionPresenter(context.getApplicationContext());
+            }
+            return sInstance;
+        }
+    }
+
+    private RuntimePermissionPresenter(Context context) {
+        mRemoteService = new RemoteService(context);
+    }
+
+    /**
+     * Gets the runtime permissions for an app.
+     *
+     * @param packageName The package for which to query.
+     * @param callback Callback to receive the result.
+     * @param handler Handler on which to invoke the callback.
+     */
+    public void getAppPermissions(@NonNull String packageName,
+            @NonNull OnResultCallback callback, @Nullable Handler handler) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = packageName;
+        args.arg2 = callback;
+        args.arg3 = handler;
+        Message message = mRemoteService.obtainMessage(
+                RemoteService.MSG_GET_APP_PERMISSIONS, args);
+        mRemoteService.processMessage(message);
+    }
+
+    /**
+     * Gets the system apps that use runtime permissions. System apps are ones
+     * that are considered system for presentation purposes instead of ones
+     * that are preinstalled on the system image. System apps are ones that
+     * are on the system image, haven't been updated (a.k.a factory apps)
+     * that do not have a launcher icon.
+     *
+     * @param system If true only system apps are returned otherwise only
+     *        non-system ones are returned.
+     * @param callback Callback to receive the result.
+     * @param handler Handler on which to invoke the callback.
+     */
+    public void getAppsUsingPermissions(boolean system, @NonNull OnResultCallback callback,
+            @Nullable Handler handler) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = callback;
+        args.arg2 = handler;
+        args.argi1 = system ? 1 : 0;
+        Message message = mRemoteService.obtainMessage(
+                RemoteService.MSG_GET_APPS_USING_PERMISSIONS, args);
+        mRemoteService.processMessage(message);
+    }
+
+    private static final class RemoteService
+            extends Handler implements ServiceConnection {
+        private static final long UNBIND_TIMEOUT_MILLIS = 10000;
+
+        public static final int MSG_GET_APP_PERMISSIONS = 1;
+        public static final int MSG_GET_APPS_USING_PERMISSIONS = 2;
+        public static final int MSG_UNBIND = 3;
+
+        private final Object mLock = new Object();
+
+        private final Context mContext;
+
+        @GuardedBy("mLock")
+        private final List<Message> mPendingWork = new ArrayList<>();
+
+        @GuardedBy("mLock")
+        private IRuntimePermissionPresenter mRemoteInstance;
+
+        @GuardedBy("mLock")
+        private boolean mBound;
+
+        public RemoteService(Context context) {
+            super(context.getMainLooper(), null, false);
+            mContext = context;
+        }
+
+        public void processMessage(Message message) {
+            synchronized (mLock) {
+                if (!mBound) {
+                    Intent intent = new Intent(
+                            RuntimePermissionPresenterService.SERVICE_INTERFACE);
+                    intent.setPackage(mContext.getPackageManager()
+                            .getPermissionControllerPackageName());
+                    mBound = mContext.bindService(intent, this,
+                            Context.BIND_AUTO_CREATE);
+                }
+                mPendingWork.add(message);
+                scheduleNextMessageIfNeededLocked();
+            }
+        }
+
+        @Override
+        public void onServiceConnected(ComponentName name, IBinder service) {
+            synchronized (mLock) {
+                mRemoteInstance = IRuntimePermissionPresenter.Stub.asInterface(service);
+                scheduleNextMessageIfNeededLocked();
+            }
+        }
+
+        @Override
+        public void onServiceDisconnected(ComponentName name) {
+            synchronized (mLock) {
+                mRemoteInstance = null;
+            }
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_GET_APP_PERMISSIONS: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final String packageName = (String) args.arg1;
+                    final OnResultCallback callback = (OnResultCallback) args.arg2;
+                    final Handler handler = (Handler) args.arg3;
+                    args.recycle();
+                    final IRuntimePermissionPresenter remoteInstance;
+                    synchronized (mLock) {
+                        remoteInstance = mRemoteInstance;
+                    }
+                    if (remoteInstance == null) {
+                        return;
+                    }
+                    try {
+                        remoteInstance.getAppPermissions(packageName,
+                                new RemoteCallback(new RemoteCallback.OnResultListener() {
+                            @Override
+                            public void onResult(Bundle result) {
+                                final List<RuntimePermissionPresentationInfo> reportedPermissions;
+                                List<RuntimePermissionPresentationInfo> permissions = null;
+                                if (result != null) {
+                                    permissions = result.getParcelableArrayList(KEY_RESULT);
+                                }
+                                if (permissions == null) {
+                                    permissions = Collections.emptyList();
+                                }
+                                reportedPermissions = permissions;
+                                if (handler != null) {
+                                    handler.post(new Runnable() {
+                                        @Override
+                                        public void run() {
+                                            callback.onGetAppPermissions(reportedPermissions);
+                                        }
+                                    });
+                                } else {
+                                    callback.onGetAppPermissions(reportedPermissions);
+                                }
+                            }
+                        }, this));
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Error getting app permissions", re);
+                    }
+                    scheduleUnbind();
+                } break;
+
+                case MSG_GET_APPS_USING_PERMISSIONS: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    final OnResultCallback callback = (OnResultCallback) args.arg1;
+                    final Handler handler = (Handler) args.arg2;
+                    final boolean system = args.argi1 == 1;
+                    args.recycle();
+                    final IRuntimePermissionPresenter remoteInstance;
+                    synchronized (mLock) {
+                        remoteInstance = mRemoteInstance;
+                    }
+                    if (remoteInstance == null) {
+                        return;
+                    }
+                    try {
+                        remoteInstance.getAppsUsingPermissions(system, new RemoteCallback(
+                                new RemoteCallback.OnResultListener() {
+                            @Override
+                            public void onResult(Bundle result) {
+                                final List<ApplicationInfo> reportedApps;
+                                List<ApplicationInfo> apps = null;
+                                if (result != null) {
+                                    apps = result.getParcelableArrayList(KEY_RESULT);
+                                }
+                                if (apps == null) {
+                                    apps = Collections.emptyList();
+                                }
+                                reportedApps = apps;
+                                if (handler != null) {
+                                    handler.post(new Runnable() {
+                                        @Override
+                                        public void run() {
+                                            callback.getAppsUsingPermissions(system, reportedApps);
+                                        }
+                                    });
+                                } else {
+                                    callback.getAppsUsingPermissions(system, reportedApps);
+                                }
+                            }
+                        }, this));
+                    } catch (RemoteException re) {
+                        Log.e(TAG, "Error getting apps using permissions", re);
+                    }
+                    scheduleUnbind();
+                } break;
+
+                case MSG_UNBIND: {
+                    synchronized (mLock) {
+                        if (mBound) {
+                            mContext.unbindService(this);
+                            mBound = false;
+                        }
+                        mRemoteInstance = null;
+                    }
+                } break;
+            }
+
+            synchronized (mLock) {
+                scheduleNextMessageIfNeededLocked();
+            }
+        }
+
+        private void scheduleNextMessageIfNeededLocked() {
+            if (mBound && mRemoteInstance != null && !mPendingWork.isEmpty()) {
+                Message nextMessage = mPendingWork.remove(0);
+                sendMessage(nextMessage);
+            }
+        }
+
+        private void scheduleUnbind() {
+            removeMessages(MSG_UNBIND);
+            sendEmptyMessageDelayed(MSG_UNBIND, UNBIND_TIMEOUT_MILLIS);
+        }
+    }
+}
diff --git a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
index 5573896..6736d34 100644
--- a/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
+++ b/core/java/android/hardware/camera2/impl/CameraCaptureSessionImpl.java
@@ -628,7 +628,12 @@
      * close the camera further by unconfiguring and then firing {@code onClosed}.</p>
      */
     private void finishPendingSequence(int sequenceId) {
-        mSequenceDrainer.taskFinished(sequenceId);
+        try {
+            mSequenceDrainer.taskFinished(sequenceId);
+        } catch (IllegalStateException e) {
+            // Workaround for b/27870771
+            Log.w(TAG, e.getMessage());
+        }
     }
 
     private class SequenceDrainListener implements TaskDrainer.DrainListener {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index 271ec79..1ff2e8a 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -590,7 +590,7 @@
         if (mService != null) try {
             mRemovalCallback = callback;
             mRemovalFingerprint = fp;
-            mService.remove(mToken, fp.getFingerId(), userId, mServiceReceiver);
+            mService.remove(mToken, fp.getFingerId(), fp.getGroupId(), userId, mServiceReceiver);
         } catch (RemoteException e) {
             Log.w(TAG, "Remote exception in remove: ", e);
             if (callback != null) {
@@ -810,11 +810,13 @@
             if (mRemovalCallback != null) {
                 int reqFingerId = mRemovalFingerprint.getFingerId();
                 int reqGroupId = mRemovalFingerprint.getGroupId();
-                if (reqFingerId != 0  &&  fingerId != reqFingerId) {
+                if (reqFingerId != 0 && fingerId != 0  &&  fingerId != reqFingerId) {
                     Log.w(TAG, "Finger id didn't match: " + fingerId + " != " + reqFingerId);
+                    return;
                 }
                 if (groupId != reqGroupId) {
                     Log.w(TAG, "Group id didn't match: " + groupId + " != " + reqGroupId);
+                    return;
                 }
                 mRemovalCallback.onRemovalSucceeded(new Fingerprint(null, groupId, fingerId,
                         deviceId));
diff --git a/core/java/android/hardware/fingerprint/IFingerprintService.aidl b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
index d7915e3..a83397a 100644
--- a/core/java/android/hardware/fingerprint/IFingerprintService.aidl
+++ b/core/java/android/hardware/fingerprint/IFingerprintService.aidl
@@ -41,7 +41,8 @@
     void cancelEnrollment(IBinder token);
 
     // Any errors resulting from this call will be returned to the listener
-    void remove(IBinder token, int fingerId, int groupId, IFingerprintServiceReceiver receiver);
+    void remove(IBinder token, int fingerId, int groupId, int userId,
+            IFingerprintServiceReceiver receiver);
 
     // Rename the fingerprint specified by fingerId and groupId to the given name
     void rename(int fingerId, int groupId, String name);
diff --git a/core/java/android/hardware/input/InputManager.java b/core/java/android/hardware/input/InputManager.java
index f810fec..8a43acb 100644
--- a/core/java/android/hardware/input/InputManager.java
+++ b/core/java/android/hardware/input/InputManager.java
@@ -19,6 +19,7 @@
 import com.android.internal.os.SomeArgs;
 
 import android.annotation.IntDef;
+import android.annotation.Nullable;
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.content.Context;
@@ -644,14 +645,16 @@
      *
      * @param identifier The identifier for the input device.
      * @param inputMethodInfo The input method.
-     * @param inputMethodSubtype The input method subtype.
+     * @param inputMethodSubtype The input method subtype. {@code null} if this input method does
+     * not support any subtype.
      *
      * @return The associated {@link KeyboardLayout}, or null if one has not been set.
      *
      * @hide
      */
+    @Nullable
     public KeyboardLayout getKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype) {
+            InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype) {
         try {
             return mIm.getKeyboardLayoutForInputDevice(
                     identifier, inputMethodInfo, inputMethodSubtype);
@@ -666,13 +669,13 @@
      * @param identifier The identifier for the input device.
      * @param inputMethodInfo The input method with which to associate the keyboard layout.
      * @param inputMethodSubtype The input method subtype which which to associate the keyboard
-     *                           layout.
+     * layout. {@code null} if this input method does not support any subtype.
      * @param keyboardLayoutDescriptor The descriptor of the keyboard layout to set
      *
      * @hide
      */
     public void setKeyboardLayoutForInputDevice(InputDeviceIdentifier identifier,
-            InputMethodInfo inputMethodInfo, InputMethodSubtype inputMethodSubtype,
+            InputMethodInfo inputMethodInfo, @Nullable InputMethodSubtype inputMethodSubtype,
             String keyboardLayoutDescriptor) {
         try {
             mIm.setKeyboardLayoutForInputDevice(identifier, inputMethodInfo,
diff --git a/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java b/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
deleted file mode 100644
index 02ab63e..0000000
--- a/core/java/android/net/metrics/CaptivePortalCheckResultEvent.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class CaptivePortalCheckResultEvent extends IpConnectivityEvent implements Parcelable {
-    public final int netId;
-    public final int result;
-
-    private CaptivePortalCheckResultEvent(int netId, int result) {
-        this.netId = netId;
-        this.result = result;
-    }
-
-    private CaptivePortalCheckResultEvent(Parcel in) {
-        this.netId = in.readInt();
-        this.result = in.readInt();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(netId);
-        out.writeInt(result);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<CaptivePortalCheckResultEvent> CREATOR
-        = new Parcelable.Creator<CaptivePortalCheckResultEvent>() {
-            public CaptivePortalCheckResultEvent createFromParcel(Parcel in) {
-                return new CaptivePortalCheckResultEvent(in);
-            }
-
-            public CaptivePortalCheckResultEvent[] newArray(int size) {
-                return new CaptivePortalCheckResultEvent[size];
-            }
-        };
-
-    public static void logEvent(int netId, int result) {
-        logEvent(IPCE_NETMON_CHECK_RESULT, new CaptivePortalCheckResultEvent(netId, result));
-    }
-};
diff --git a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java b/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
deleted file mode 100644
index aabd09b..0000000
--- a/core/java/android/net/metrics/CaptivePortalStateChangeEvent.java
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * 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.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class CaptivePortalStateChangeEvent extends IpConnectivityEvent implements Parcelable {
-    public static final int NETWORK_MONITOR_CONNECTED    = 0;
-    public static final int NETWORK_MONITOR_DISCONNECTED = 1;
-    public static final int NETWORK_MONITOR_VALIDATED    = 2;
-
-    public final int state;
-
-    public CaptivePortalStateChangeEvent(int state) {
-        this.state = state;
-    }
-
-    public CaptivePortalStateChangeEvent(Parcel in) {
-        state = in.readInt();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeInt(state);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<CaptivePortalStateChangeEvent> CREATOR
-        = new Parcelable.Creator<CaptivePortalStateChangeEvent>() {
-        public CaptivePortalStateChangeEvent createFromParcel(Parcel in) {
-            return new CaptivePortalStateChangeEvent(in);
-        }
-
-        public CaptivePortalStateChangeEvent[] newArray(int size) {
-            return new CaptivePortalStateChangeEvent[size];
-        }
-    };
-
-    public static void logEvent(int state) {
-        logEvent(IPCE_NETMON_STATE_CHANGE, new CaptivePortalStateChangeEvent(state));
-    }
-};
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/DefaultNetworkEvent.java
similarity index 69%
rename from core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
rename to core/java/android/net/metrics/DefaultNetworkEvent.java
index fce68bb..f3c357b 100644
--- a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/DefaultNetworkEvent.java
@@ -24,8 +24,7 @@
  * {@hide}
  */
 @SystemApi
-public final class ConnectivityServiceChangeEvent extends IpConnectivityEvent
-        implements Parcelable {
+public final class DefaultNetworkEvent extends IpConnectivityEvent implements Parcelable {
     // The ID of the network that has become the new default or NETID_UNSET if none.
     public final int netId;
     // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
@@ -37,7 +36,7 @@
     public final boolean prevIPv4;
     public final boolean prevIPv6;
 
-    private ConnectivityServiceChangeEvent(int netId, int[] transportTypes,
+    private DefaultNetworkEvent(int netId, int[] transportTypes,
                 int prevNetId, boolean prevIPv4, boolean prevIPv6) {
         this.netId = netId;
         this.transportTypes = transportTypes;
@@ -46,7 +45,7 @@
         this.prevIPv6 = prevIPv6;
     }
 
-    private ConnectivityServiceChangeEvent(Parcel in) {
+    private DefaultNetworkEvent(Parcel in) {
         this.netId = in.readInt();
         this.transportTypes = in.createIntArray();
         this.prevNetId = in.readInt();
@@ -66,21 +65,21 @@
         return 0;
     }
 
-    public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
-        = new Parcelable.Creator<ConnectivityServiceChangeEvent>() {
-        public ConnectivityServiceChangeEvent createFromParcel(Parcel in) {
-            return new ConnectivityServiceChangeEvent(in);
+    public static final Parcelable.Creator<DefaultNetworkEvent> CREATOR
+        = new Parcelable.Creator<DefaultNetworkEvent>() {
+        public DefaultNetworkEvent createFromParcel(Parcel in) {
+            return new DefaultNetworkEvent(in);
         }
 
-        public ConnectivityServiceChangeEvent[] newArray(int size) {
-            return new ConnectivityServiceChangeEvent[size];
+        public DefaultNetworkEvent[] newArray(int size) {
+            return new DefaultNetworkEvent[size];
         }
     };
 
-    public static void logEvent(int netId, int[] transportTypes,
-            int prevNetId, boolean prevIPv4, boolean prevIPv6) {
-        logEvent(IPCE_CONSRV_DEFAULT_NET_CHANGE,
-                new ConnectivityServiceChangeEvent(
-                        netId, transportTypes, prevNetId, prevIPv4, prevIPv6));
+    public static void logEvent(
+            int netId, int[] transports, int prevNetId, boolean hadIPv4, boolean hadIPv6) {
+        final DefaultNetworkEvent ev =
+                new DefaultNetworkEvent(netId, transports, prevNetId, hadIPv4, hadIPv6);
+        logEvent(IPCE_CONSRV_DEFAULT_NET_CHANGE, ev);
     }
 };
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index 2eb8edb..0b5e354 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -39,9 +39,10 @@
     public static final int IPCE_IPMGR_BASE                = 4 * 1024;
     public static final int IPCE_DNS_BASE                  = 5 * 1024;
 
-    public static final int IPCE_IPRM_PROBE_RESULT         = IPCE_IPRM_BASE + 0;
-    public static final int IPCE_IPRM_MESSAGE_RECEIVED     = IPCE_IPRM_BASE + 1;
-    public static final int IPCE_IPRM_REACHABILITY_LOST    = IPCE_IPRM_BASE + 2;
+    public static final int IPCE_IPRM_PROBE_STARTED        = IPCE_IPRM_BASE + 0;
+    public static final int IPCE_IPRM_PROBE_FAILURE        = IPCE_IPRM_BASE + 1;
+    public static final int IPCE_IPRM_NUD_FAILED           = IPCE_IPRM_BASE + 2;
+    public static final int IPCE_IPRM_PROVISIONING_LOST    = IPCE_IPRM_BASE + 3;
 
     public static final int IPCE_DHCP_RECV_ERROR           = IPCE_DHCP_BASE + 0;
     public static final int IPCE_DHCP_PARSE_ERROR          = IPCE_DHCP_BASE + 1;
@@ -49,6 +50,9 @@
 
     public static final int IPCE_NETMON_STATE_CHANGE       = IPCE_NETMON_BASE + 0;
     public static final int IPCE_NETMON_CHECK_RESULT       = IPCE_NETMON_BASE + 1;
+    public static final int IPCE_NETMON_VALIDATED          = IPCE_NETMON_BASE + 2;
+    public static final int IPCE_NETMON_PORTAL_PROBE       = IPCE_NETMON_BASE + 3;
+    public static final int IPCE_NETMON_CAPPORT_FOUND      = IPCE_NETMON_BASE + 4;
 
     public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
 
diff --git a/core/java/android/net/metrics/IpReachabilityEvent.java b/core/java/android/net/metrics/IpReachabilityEvent.java
new file mode 100644
index 0000000..73dcb94
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityEvent.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 android.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class IpReachabilityEvent extends IpConnectivityEvent implements Parcelable {
+
+    public static final int PROBE             = 1 << 8;
+    public static final int NUD_FAILED        = 2 << 8;
+    public static final int PROVISIONING_LOST = 3 << 8;
+
+    public final String ifName;
+    // eventType byte format (MSB to LSB):
+    // byte 0: unused
+    // byte 1: unused
+    // byte 2: type of event: PROBE, NUD_FAILED, PROVISIONING_LOST
+    // byte 3: kernel errno from RTNetlink or IpReachabilityMonitor
+    public final int eventType;
+
+    private IpReachabilityEvent(String ifName, int eventType) {
+        this.ifName = ifName;
+        this.eventType = eventType;
+    }
+
+    private IpReachabilityEvent(Parcel in) {
+        this.ifName = in.readString();
+        this.eventType = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(ifName);
+        out.writeInt(eventType);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<IpReachabilityEvent> CREATOR
+        = new Parcelable.Creator<IpReachabilityEvent>() {
+        public IpReachabilityEvent createFromParcel(Parcel in) {
+            return new IpReachabilityEvent(in);
+        }
+
+        public IpReachabilityEvent[] newArray(int size) {
+            return new IpReachabilityEvent[size];
+        }
+    };
+
+    public static void logProbeEvent(String ifName, int nlErrorCode) {
+        final int tag = (nlErrorCode == 0) ? IPCE_IPRM_PROBE_STARTED : IPCE_IPRM_PROBE_FAILURE;
+        final int eventType = PROBE | (nlErrorCode & 0xFF);
+        logEvent(tag, new IpReachabilityEvent(ifName, eventType));
+    }
+
+    public static void logNudFailed(String ifName) {
+        logEvent(IPCE_IPRM_NUD_FAILED, new IpReachabilityEvent(ifName, NUD_FAILED));
+    }
+
+    public static void logProvisioningLost(String ifName) {
+        logEvent(IPCE_IPRM_PROVISIONING_LOST, new IpReachabilityEvent(ifName, PROVISIONING_LOST));
+    }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
deleted file mode 100644
index 5215995..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- * 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.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
-        implements Parcelable {
-    public final String ifName;
-
-    private IpReachabilityMonitorLostEvent(String ifName) {
-        this.ifName = ifName;
-    }
-
-    private IpReachabilityMonitorLostEvent(Parcel in) {
-        this.ifName = in.readString();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ifName);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
-        = new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
-        public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
-            return new IpReachabilityMonitorLostEvent(in);
-        }
-
-        public IpReachabilityMonitorLostEvent[] newArray(int size) {
-            return new IpReachabilityMonitorLostEvent[size];
-        }
-    };
-
-    public static void logEvent(String ifName) {
-        logEvent(IPCE_IPRM_REACHABILITY_LOST, new IpReachabilityMonitorLostEvent(ifName));
-    }
-};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
deleted file mode 100644
index 0ed8c1c..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorMessageEvent.java
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorMessageEvent extends IpConnectivityEvent
-        implements Parcelable {
-    public final String ifName;
-    public final String destination;
-    public final int msgType;
-    public final int nudState;
-
-    private IpReachabilityMonitorMessageEvent(String ifName, String destination, int msgType,
-            int nudState) {
-        this.ifName = ifName;
-        this.destination = destination;
-        this.msgType = msgType;
-        this.nudState = nudState;
-    }
-
-    private IpReachabilityMonitorMessageEvent(Parcel in) {
-        this.ifName = in.readString();
-        this.destination = in.readString();
-        this.msgType = in.readInt();
-        this.nudState = in.readInt();
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ifName);
-        out.writeString(destination);
-        out.writeInt(msgType);
-        out.writeInt(nudState);
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<IpReachabilityMonitorMessageEvent> CREATOR
-        = new Parcelable.Creator<IpReachabilityMonitorMessageEvent>() {
-        public IpReachabilityMonitorMessageEvent createFromParcel(Parcel in) {
-            return new IpReachabilityMonitorMessageEvent(in);
-        }
-
-        public IpReachabilityMonitorMessageEvent[] newArray(int size) {
-            return new IpReachabilityMonitorMessageEvent[size];
-        }
-    };
-
-    public static void logEvent(String ifName, String destination, int msgType, int nudState) {
-        logEvent(IPCE_IPRM_MESSAGE_RECEIVED,
-                new IpReachabilityMonitorMessageEvent(ifName, destination, msgType, nudState));
-    }
-};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
deleted file mode 100644
index a55c2b4..0000000
--- a/core/java/android/net/metrics/IpReachabilityMonitorProbeEvent.java
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- * 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.net.metrics;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * {@hide}
- */
-@SystemApi
-public final class IpReachabilityMonitorProbeEvent extends IpConnectivityEvent
-        implements Parcelable {
-    public final String ifName;
-    public final String destination;
-    public final boolean success;
-
-    private IpReachabilityMonitorProbeEvent(String ifName, String destination, boolean success) {
-        this.ifName = ifName;
-        this.destination = destination;
-        this.success = success;
-    }
-
-    private IpReachabilityMonitorProbeEvent(Parcel in) {
-        this.ifName = in.readString();
-        this.destination = in.readString();
-        this.success = in.readByte() > 0 ? true : false;
-    }
-
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(ifName);
-        out.writeString(destination);
-        out.writeByte((byte)(success ? 1 : 0));
-    }
-
-    public int describeContents() {
-        return 0;
-    }
-
-    public static final Parcelable.Creator<IpReachabilityMonitorProbeEvent> CREATOR
-        = new Parcelable.Creator<IpReachabilityMonitorProbeEvent>() {
-        public IpReachabilityMonitorProbeEvent createFromParcel(Parcel in) {
-            return new IpReachabilityMonitorProbeEvent(in);
-        }
-
-        public IpReachabilityMonitorProbeEvent[] newArray(int size) {
-            return new IpReachabilityMonitorProbeEvent[size];
-        }
-    };
-
-    public static void logEvent(String ifName, String destination, boolean success) {
-        logEvent(IPCE_IPRM_PROBE_RESULT,
-                new IpReachabilityMonitorProbeEvent(ifName, destination, success));
-    }
-};
diff --git a/core/java/android/net/metrics/NetworkEvent.java b/core/java/android/net/metrics/NetworkEvent.java
new file mode 100644
index 0000000..b15dcee
--- /dev/null
+++ b/core/java/android/net/metrics/NetworkEvent.java
@@ -0,0 +1,86 @@
+/*
+ * 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.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class NetworkEvent extends IpConnectivityEvent implements Parcelable {
+
+    public static final int NETWORK_CONNECTED            = 1;
+    public static final int NETWORK_VALIDATED            = 2;
+    public static final int NETWORK_VALIDATION_FAILED    = 3;
+    public static final int NETWORK_CAPTIVE_PORTAL_FOUND = 4;
+    public static final int NETWORK_LINGER               = 5;
+    public static final int NETWORK_UNLINGER             = 6;
+    public static final int NETWORK_DISCONNECTED         = 7;
+
+    public final int netId;
+    public final int eventType;
+    public final long durationMs;
+
+    private NetworkEvent(int netId, int eventType, long durationMs) {
+        this.netId = netId;
+        this.eventType = eventType;
+        this.durationMs = durationMs;
+    }
+
+    private NetworkEvent(Parcel in) {
+        netId = in.readInt();
+        eventType = in.readInt();
+        durationMs = in.readLong();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(netId);
+        out.writeInt(eventType);
+        out.writeLong(durationMs);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<NetworkEvent> CREATOR
+        = new Parcelable.Creator<NetworkEvent>() {
+        public NetworkEvent createFromParcel(Parcel in) {
+            return new NetworkEvent(in);
+        }
+
+        public NetworkEvent[] newArray(int size) {
+            return new NetworkEvent[size];
+        }
+    };
+
+    public static void logEvent(int netId, int eventType) {
+        logEvent(IPCE_NETMON_STATE_CHANGE, new NetworkEvent(netId, eventType, 0));
+    }
+
+    public static void logValidated(int netId, long durationMs) {
+        logEvent(IPCE_NETMON_VALIDATED, new NetworkEvent(netId, NETWORK_VALIDATED, durationMs));
+    }
+
+    public static void logCaptivePortalFound(int netId, long durationMs) {
+        final NetworkEvent ev = new NetworkEvent(netId, NETWORK_CAPTIVE_PORTAL_FOUND, durationMs);
+        logEvent(IPCE_NETMON_CAPPORT_FOUND, ev);
+    }
+};
diff --git a/core/java/android/net/metrics/ValidationProbeEvent.java b/core/java/android/net/metrics/ValidationProbeEvent.java
new file mode 100644
index 0000000..0a524c6
--- /dev/null
+++ b/core/java/android/net/metrics/ValidationProbeEvent.java
@@ -0,0 +1,77 @@
+/*
+ * 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.net.metrics;
+
+import android.annotation.SystemApi;
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+@SystemApi
+public final class ValidationProbeEvent extends IpConnectivityEvent implements Parcelable {
+
+    public static final int PROBE_HTTP  = 0;
+    public static final int PROBE_HTTPS = 1;
+
+    public final int netId;
+    public final long durationMs;
+    public final int probeType;
+    public final int returnCode;
+
+    private ValidationProbeEvent(int netId, long durationMs, int probeType, int returnCode) {
+        this.netId = netId;
+        this.durationMs = durationMs;
+        this.probeType = probeType;
+        this.returnCode = returnCode;
+    }
+
+    private ValidationProbeEvent(Parcel in) {
+        netId = in.readInt();
+        durationMs = in.readLong();
+        probeType = in.readInt();
+        returnCode = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(netId);
+        out.writeLong(durationMs);
+        out.writeInt(probeType);
+        out.writeInt(returnCode);
+    }
+
+    public int describeContents() {
+        return 0;
+    }
+
+    public static final Parcelable.Creator<ValidationProbeEvent> CREATOR
+        = new Parcelable.Creator<ValidationProbeEvent>() {
+        public ValidationProbeEvent createFromParcel(Parcel in) {
+            return new ValidationProbeEvent(in);
+        }
+
+        public ValidationProbeEvent[] newArray(int size) {
+            return new ValidationProbeEvent[size];
+        }
+    };
+
+    public static void logEvent(int netId, long durationMs, int probeType, int returnCode) {
+        logEvent(IPCE_NETMON_PORTAL_PROBE,
+                 new ValidationProbeEvent(netId, durationMs, probeType, returnCode));
+    }
+};
diff --git a/core/java/android/os/Build.java b/core/java/android/os/Build.java
index d0029e1..7e1fc15 100644
--- a/core/java/android/os/Build.java
+++ b/core/java/android/os/Build.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.SystemApi;
 import android.text.TextUtils;
 import android.util.Slog;
 
@@ -802,6 +803,7 @@
      *
      * @hide
      */
+    @SystemApi
     public static final boolean PERMISSIONS_REVIEW_REQUIRED =
             SystemProperties.getInt("ro.permission_review_required", 0) == 1;
 
diff --git a/core/java/android/os/PowerManager.java b/core/java/android/os/PowerManager.java
index 92edc62..c285acb 100644
--- a/core/java/android/os/PowerManager.java
+++ b/core/java/android/os/PowerManager.java
@@ -219,15 +219,6 @@
     public static final int DRAW_WAKE_LOCK = 0x00000080;
 
     /**
-     * Wake lock level: Enables Sustained Performance Mode.
-     * <p>
-     * This is used by Gaming and VR applications to ensure the device
-     * will provide consistent performance over a large amount of time.
-     * </p>
-     */
-    public static final int SUSTAINED_PERFORMANCE_WAKE_LOCK = 0x00000100;
-
-    /**
      * Mask for the wake lock level component of a combined wake lock level and flags integer.
      *
      * @hide
@@ -559,7 +550,6 @@
             case PROXIMITY_SCREEN_OFF_WAKE_LOCK:
             case DOZE_WAKE_LOCK:
             case DRAW_WAKE_LOCK:
-            case SUSTAINED_PERFORMANCE_WAKE_LOCK:
                 break;
             default:
                 throw new IllegalArgumentException("Must specify a valid wake lock level.");
@@ -1033,7 +1023,7 @@
     /**
      * Returns True if the device supports Sustained Performance Mode.
      * Applications Should check if the device supports this mode, before
-     * using {@link #SUSTAINED_PERFORMANCE_WAKE_LOCK}.
+     * using {@link android.view.Window#setSustainedPerformanceMode}.
      */
     public boolean isSustainedPerformanceModeSupported() {
         return mContext.getResources().getBoolean(
diff --git a/core/java/android/os/RemoteCallback.java b/core/java/android/os/RemoteCallback.java
index 89e30a9..7dbcb95 100644
--- a/core/java/android/os/RemoteCallback.java
+++ b/core/java/android/os/RemoteCallback.java
@@ -18,10 +18,12 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.annotation.SystemApi;
 
 /**
  * @hide
  */
+@SystemApi
 public final class RemoteCallback implements Parcelable {
 
     public interface OnResultListener {
diff --git a/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
new file mode 100644
index 0000000..405be1a
--- /dev/null
+++ b/core/java/android/permissionpresenterservice/RuntimePermissionPresenterService.java
@@ -0,0 +1,146 @@
+/*
+ * 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.permissionpresenterservice;
+
+import android.annotation.SystemApi;
+import android.app.Service;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.permission.IRuntimePermissionPresenter;
+import android.content.pm.permission.RuntimePermissionPresentationInfo;
+import android.content.pm.permission.RuntimePermissionPresenter;
+import android.os.Bundle;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteCallback;
+import com.android.internal.os.SomeArgs;
+
+import java.util.List;
+
+/**
+ * This service presents information regarding runtime permissions that is
+ * used for presenting them in the UI. Runtime permissions are presented as
+ * a single permission in the UI but may be composed of several individual
+ * permissions.
+ *
+ * @see RuntimePermissionPresenter
+ * @see RuntimePermissionPresentationInfo
+ *
+ * @hide
+ */
+@SystemApi
+public abstract class RuntimePermissionPresenterService extends Service {
+
+    /**
+     * The {@link Intent} action that must be declared as handled by a service
+     * in its manifest for the system to recognize it as a runtime permission
+     * presenter service.
+     */
+    public static final String SERVICE_INTERFACE =
+            "android.permissionpresenterservice.RuntimePermissionPresenterService";
+
+    // No need for locking - always set first and never modified
+    private Handler mHandler;
+
+    @Override
+    public final void attachBaseContext(Context base) {
+        super.attachBaseContext(base);
+        mHandler = new MyHandler(base.getMainLooper());
+    }
+
+    /**
+     * Gets the runtime permissions for an app.
+     *
+     * @param packageName The package for which to query.
+     */
+    public abstract List<RuntimePermissionPresentationInfo> onGetAppPermissions(String packageName);
+
+    /**
+     * Gets the apps that use runtime permissions.
+     *
+     * @param system Whether to return only the system apps or only the non-system ones.
+     * @return The app list.
+     */
+    public abstract List<ApplicationInfo> onGetAppsUsingPermissions(boolean system);
+
+    @Override
+    public final IBinder onBind(Intent intent) {
+        return new IRuntimePermissionPresenter.Stub() {
+            @Override
+            public void getAppPermissions(String packageName, RemoteCallback callback) {
+                SomeArgs args = SomeArgs.obtain();
+                args.arg1 = packageName;
+                args.arg2 = callback;
+                mHandler.obtainMessage(MyHandler.MSG_GET_APP_PERMISSIONS,
+                        args).sendToTarget();
+            }
+
+            @Override
+            public void getAppsUsingPermissions(boolean system, RemoteCallback callback) {
+                mHandler.obtainMessage(MyHandler.MSG_GET_APPS_USING_PERMISSIONS,
+                        system ? 1 : 0, 0, callback).sendToTarget();
+            }
+        };
+    }
+
+    private final class MyHandler extends Handler {
+        public static final int MSG_GET_APP_PERMISSIONS = 1;
+        public static final int MSG_GET_APPS_USING_PERMISSIONS = 2;
+
+        public MyHandler(Looper looper) {
+            super(looper, null, false);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_GET_APP_PERMISSIONS: {
+                    SomeArgs args = (SomeArgs) msg.obj;
+                    String packageName = (String) args.arg1;
+                    RemoteCallback callback = (RemoteCallback) args.arg2;
+                    args.recycle();
+                    List<RuntimePermissionPresentationInfo> permissions =
+                            onGetAppPermissions(packageName);
+                    if (permissions != null && !permissions.isEmpty()) {
+                        Bundle result = new Bundle();
+                        result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT,
+                                permissions);
+                        callback.sendResult(result);
+                    } else {
+                        callback.sendResult(null);
+                    }
+                } break;
+
+                case MSG_GET_APPS_USING_PERMISSIONS: {
+                    RemoteCallback callback = (RemoteCallback) msg.obj;
+                    final boolean system = msg.arg1 == 1;
+                    List<ApplicationInfo> apps = onGetAppsUsingPermissions(system);
+                    if (apps != null && !apps.isEmpty()) {
+                        Bundle result = new Bundle();
+                        result.putParcelableList(RuntimePermissionPresenter.KEY_RESULT, apps);
+                        callback.sendResult(result);
+                    } else {
+                        callback.sendResult(null);
+                    }
+                } break;
+            }
+        }
+    }
+}
diff --git a/core/java/android/print/PrintAttributes.java b/core/java/android/print/PrintAttributes.java
index 721c94e..17942ae 100644
--- a/core/java/android/print/PrintAttributes.java
+++ b/core/java/android/print/PrintAttributes.java
@@ -805,8 +805,8 @@
          * @param id The unique media size id.
          * @param packageName The name of the creating package.
          * @param labelResId The resource if of a human readable label.
-         * @param widthMils The width in mils (thousands of an inch).
-         * @param heightMils The height in mils (thousands of an inch).
+         * @param widthMils The width in mils (thousandths of an inch).
+         * @param heightMils The height in mils (thousandths of an inch).
          *
          * @throws IllegalArgumentException If the id is empty or the label
          * is empty or the widthMils is less than or equal to zero or the
@@ -828,8 +828,8 @@
          * @param id The unique media size id. It is unique amongst other media sizes
          *        supported by the printer.
          * @param label The <strong>localized</strong> human readable label.
-         * @param widthMils The width in mils (thousands of an inch).
-         * @param heightMils The height in mils (thousands of an inch).
+         * @param widthMils The width in mils (thousandths of an inch).
+         * @param heightMils The height in mils (thousandths of an inch).
          *
          * @throws IllegalArgumentException If the id is empty or the label is empty
          * or the widthMils is less than or equal to zero or the heightMils is less
@@ -864,8 +864,8 @@
          *        supported by the printer.
          * @param label The <strong>localized</strong> human readable label.
          * @param packageName The name of the creating package.
-         * @param widthMils The width in mils (thousands of an inch).
-         * @param heightMils The height in mils (thousands of an inch).
+         * @param widthMils The width in mils (thousandths of an inch).
+         * @param heightMils The height in mils (thousandths of an inch).
          * @param labelResId The resource if of a human readable label.
          *
          * @throws IllegalArgumentException If the id is empty or the label is unset
@@ -924,7 +924,7 @@
         }
 
         /**
-         * Gets the media width in mils (thousands of an inch).
+         * Gets the media width in mils (thousandths of an inch).
          *
          * @return The media width.
          */
@@ -933,7 +933,7 @@
         }
 
         /**
-         * Gets the media height in mils (thousands of an inch).
+         * Gets the media height in mils (thousandths of an inch).
          *
          * @return The media height.
          */
@@ -1225,10 +1225,10 @@
         /**
          * Creates a new instance.
          *
-         * @param leftMils The left margin in mils (thousands of an inch).
-         * @param topMils The top margin in mils (thousands of an inch).
-         * @param rightMils The right margin in mils (thousands of an inch).
-         * @param bottomMils The bottom margin in mils (thousands of an inch).
+         * @param leftMils The left margin in mils (thousandths of an inch).
+         * @param topMils The top margin in mils (thousandths of an inch).
+         * @param rightMils The right margin in mils (thousandths of an inch).
+         * @param bottomMils The bottom margin in mils (thousandths of an inch).
          */
         public Margins(int leftMils, int topMils, int rightMils, int bottomMils) {
             mTopMils = topMils;
@@ -1238,7 +1238,7 @@
         }
 
         /**
-         * Gets the left margin in mils (thousands of an inch).
+         * Gets the left margin in mils (thousandths of an inch).
          *
          * @return The left margin.
          */
@@ -1247,7 +1247,7 @@
         }
 
         /**
-         * Gets the top margin in mils (thousands of an inch).
+         * Gets the top margin in mils (thousandths of an inch).
          *
          * @return The top margin.
          */
@@ -1256,7 +1256,7 @@
         }
 
         /**
-         * Gets the right margin in mils (thousands of an inch).
+         * Gets the right margin in mils (thousandths of an inch).
          *
          * @return The right margin.
          */
@@ -1265,7 +1265,7 @@
         }
 
         /**
-         * Gets the bottom margin in mils (thousands of an inch).
+         * Gets the bottom margin in mils (thousandths of an inch).
          *
          * @return The bottom margin.
          */
diff --git a/core/java/android/print/PrintManager.java b/core/java/android/print/PrintManager.java
index 71f0bd6..5d0ad55 100644
--- a/core/java/android/print/PrintManager.java
+++ b/core/java/android/print/PrintManager.java
@@ -778,6 +778,12 @@
 
         public PrintDocumentAdapterDelegate(Activity activity,
                 PrintDocumentAdapter documentAdapter) {
+            if (activity.isFinishing()) {
+                // The activity is already dead hence the onActivityDestroyed callback won't be
+                // triggered. Hence it is not save to print in this situation.
+                throw new IllegalStateException("Cannot start printing for finishing activity");
+            }
+
             mActivity = activity;
             mDocumentAdapter = documentAdapter;
             mHandler = new MyHandler(mActivity.getMainLooper());
diff --git a/core/java/android/printservice/CustomPrinterIconCallback.java b/core/java/android/printservice/CustomPrinterIconCallback.java
index 6b9d0d8..a1fbdab 100644
--- a/core/java/android/printservice/CustomPrinterIconCallback.java
+++ b/core/java/android/printservice/CustomPrinterIconCallback.java
@@ -27,7 +27,7 @@
 /**
  * Callback for {@link PrinterDiscoverySession#onRequestCustomPrinterIcon}.
  */
-public class CustomPrinterIconCallback {
+public final class CustomPrinterIconCallback {
     /** The printer the call back is for */
     private final @NonNull PrinterId mPrinterId;
     private final @NonNull IPrintServiceClient mObserver;
diff --git a/core/java/android/printservice/PrintJob.java b/core/java/android/printservice/PrintJob.java
index 7a7ca23..3226f34 100644
--- a/core/java/android/printservice/PrintJob.java
+++ b/core/java/android/printservice/PrintJob.java
@@ -347,18 +347,15 @@
      * <p />
      * This overrides any previously set status set via {@link #setStatus(CharSequence)},
      * {@link #setStatus(int)}, {@link #block(String)}, or {@link #fail(String)},
-     * <p />
-     * To clear the status use {@link #setStatus(CharSequence) <code>setStatus(null)</code>}
      *
-     * @param status  The new status as a String resource.
+     * @param statusResId The new status as a String resource. If 0 the status will be empty.
      */
     @MainThread
-    public void setStatus(@StringRes int status) {
+    public void setStatus(@StringRes int statusResId) {
         PrintService.throwIfNotCalledOnMainThread();
-        Preconditions.checkArgument(status != 0, "status has to be != 0");
 
         try {
-            mPrintServiceClient.setStatusRes(mCachedInfo.getId(), status,
+            mPrintServiceClient.setStatusRes(mCachedInfo.getId(), statusResId,
                     mContext.getPackageName());
         } catch (RemoteException re) {
             Log.e(LOG_TAG, "Error setting status for job: " + mCachedInfo.getId(), re);
diff --git a/core/java/android/printservice/PrinterDiscoverySession.java b/core/java/android/printservice/PrinterDiscoverySession.java
index 7b9533d..4987e8b 100644
--- a/core/java/android/printservice/PrinterDiscoverySession.java
+++ b/core/java/android/printservice/PrinterDiscoverySession.java
@@ -408,15 +408,15 @@
     public abstract void onStartPrinterStateTracking(@NonNull PrinterId printerId);
 
     /**
-     * Request the custom icon for a printer. Once the icon is available use
-     * {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the data to the print
-     * service.
+     * Called by the system to request the custom icon for a printer. Once the icon is available the
+     * print services uses {@link CustomPrinterIconCallback#onCustomPrinterIconLoaded} to send the
+     * icon to the system.
      *
      * @param printerId The printer to icon belongs to.
-     * @param cancellationSignal Signal used to cancel the request
-     * @param callback Callback for returning the icon to the print spooler.
+     * @param cancellationSignal Signal used to cancel the request.
+     * @param callback Callback for returning the icon to the system.
      *
-     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon()
+     * @see android.print.PrinterInfo.Builder#setHasCustomPrinterIcon(boolean)
      */
     public void onRequestCustomPrinterIcon(@NonNull PrinterId printerId,
             @NonNull CancellationSignal cancellationSignal,
diff --git a/core/java/android/view/DropPermissions.java b/core/java/android/view/DragAndDropPermissions.java
similarity index 69%
rename from core/java/android/view/DropPermissions.java
rename to core/java/android/view/DragAndDropPermissions.java
index 5411dad..a3dbdb1 100644
--- a/core/java/android/view/DropPermissions.java
+++ b/core/java/android/view/DragAndDropPermissions.java
@@ -19,51 +19,52 @@
 import android.app.ActivityManagerNative;
 import android.os.IBinder;
 import android.os.RemoteException;
-import com.android.internal.view.IDropPermissions;
+import com.android.internal.view.IDragAndDropPermissions;
 import dalvik.system.CloseGuard;
 
 
 /**
- * {@link DropPermissions} controls the access permissions for the content URIs associated with a
- * {@link DragEvent}.
+ * {@link DragAndDropPermissions} controls the access permissions for the content URIs associated
+ * with a {@link DragEvent}.
  * <p>
  * Permission are granted when this object is created by {@link
- * android.app.Activity#requestDropPermissions(DragEvent) Activity.requestDropPermissions}.
+ * android.app.Activity#requestDragAndDropPermissions(DragEvent)
+ * Activity.requestDragAndDropPermissions}.
  * Which permissions are granted is defined by the set of flags passed to {@link
  * View#startDragAndDrop(android.content.ClipData, View.DragShadowBuilder, Object, int)
  * View.startDragAndDrop} by the app that started the drag operation.
  * <p>
  * The life cycle of the permissions is bound to the activity used to call {@link
- * android.app.Activity#requestDropPermissions(DragEvent) requestDropPermissions}. The
+ * android.app.Activity#requestDragAndDropPermissions(DragEvent) requestDragAndDropPermissions}. The
  * permissions are revoked when this activity is destroyed, or when {@link #release()} is called,
  * whichever occurs first.
  */
-public final class DropPermissions {
+public final class DragAndDropPermissions {
 
-    private final IDropPermissions mDropPermissions;
+    private final IDragAndDropPermissions mDragAndDropPermissions;
 
     private IBinder mPermissionOwnerToken;
 
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     /**
-     * Create a new {@link DropPermissions} object to control the access permissions for content
-     * URIs associated with {@link DragEvent}.
+     * Create a new {@link DragAndDropPermissions} object to control the access permissions for
+     * content URIs associated with {@link DragEvent}.
      * @param dragEvent Drag event
-     * @return {@link DropPermissions} object or null if there are no content URIs associated with
-     * the {@link DragEvent}.
+     * @return {@link DragAndDropPermissions} object or null if there are no content URIs associated
+     * with the {@link DragEvent}.
      * @hide
      */
-    public static DropPermissions obtain(DragEvent dragEvent) {
-        if (dragEvent.getDropPermissions() == null) {
+    public static DragAndDropPermissions obtain(DragEvent dragEvent) {
+        if (dragEvent.getDragAndDropPermissions() == null) {
             return null;
         }
-        return new DropPermissions(dragEvent.getDropPermissions());
+        return new DragAndDropPermissions(dragEvent.getDragAndDropPermissions());
     }
 
     /** @hide */
-    private DropPermissions(IDropPermissions dropPermissions) {
-        mDropPermissions = dropPermissions;
+    private DragAndDropPermissions(IDragAndDropPermissions dragAndDropPermissions) {
+        mDragAndDropPermissions = dragAndDropPermissions;
     }
 
     /**
@@ -74,7 +75,7 @@
      */
     public boolean take(IBinder activityToken) {
         try {
-            mDropPermissions.take(activityToken);
+            mDragAndDropPermissions.take(activityToken);
         } catch (RemoteException e) {
             return false;
         }
@@ -91,7 +92,7 @@
         try {
             mPermissionOwnerToken = ActivityManagerNative.getDefault().
                     newUriPermissionOwner("drop");
-            mDropPermissions.takeTransient(mPermissionOwnerToken);
+            mDragAndDropPermissions.takeTransient(mPermissionOwnerToken);
         } catch (RemoteException e) {
             return false;
         }
@@ -104,7 +105,7 @@
      */
     public void release() {
         try {
-            mDropPermissions.release();
+            mDragAndDropPermissions.release();
             mPermissionOwnerToken = null;
         } catch (RemoteException e) {
         }
diff --git a/core/java/android/view/DragEvent.java b/core/java/android/view/DragEvent.java
index 71db0b5..0dfbe70 100644
--- a/core/java/android/view/DragEvent.java
+++ b/core/java/android/view/DragEvent.java
@@ -21,7 +21,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
-import com.android.internal.view.IDropPermissions;
+import com.android.internal.view.IDragAndDropPermissions;
 
 //TODO: Improve Javadoc
 /**
@@ -130,7 +130,7 @@
     float mX, mY;
     ClipDescription mClipDescription;
     ClipData mClipData;
-    IDropPermissions mDropPermissions;
+    IDragAndDropPermissions mDragAndDropPermissions;
 
     Object mLocalState;
     boolean mDragResult;
@@ -257,13 +257,13 @@
     }
 
     private void init(int action, float x, float y, ClipDescription description, ClipData data,
-            IDropPermissions dropPermissions, Object localState, boolean result) {
+            IDragAndDropPermissions dragAndDropPermissions, Object localState, boolean result) {
         mAction = action;
         mX = x;
         mY = y;
         mClipDescription = description;
         mClipData = data;
-        mDropPermissions = dropPermissions;
+        this.mDragAndDropPermissions = dragAndDropPermissions;
         mLocalState = localState;
         mDragResult = result;
     }
@@ -274,13 +274,14 @@
 
     /** @hide */
     public static DragEvent obtain(int action, float x, float y, Object localState,
-            ClipDescription description, ClipData data, IDropPermissions dropPermissions,
-            boolean result) {
+            ClipDescription description, ClipData data,
+            IDragAndDropPermissions dragAndDropPermissions, boolean result) {
         final DragEvent ev;
         synchronized (gRecyclerLock) {
             if (gRecyclerTop == null) {
                 ev = new DragEvent();
-                ev.init(action, x, y, description, data, dropPermissions, localState, result);
+                ev.init(action, x, y, description, data, dragAndDropPermissions, localState,
+                        result);
                 return ev;
             }
             ev = gRecyclerTop;
@@ -291,7 +292,7 @@
         ev.mRecycled = false;
         ev.mNext = null;
 
-        ev.init(action, x, y, description, data, dropPermissions, localState, result);
+        ev.init(action, x, y, description, data, dragAndDropPermissions, localState, result);
 
         return ev;
     }
@@ -299,7 +300,7 @@
     /** @hide */
     public static DragEvent obtain(DragEvent source) {
         return obtain(source.mAction, source.mX, source.mY, source.mLocalState,
-                source.mClipDescription, source.mClipData, source.mDropPermissions,
+                source.mClipDescription, source.mClipData, source.mDragAndDropPermissions,
                 source.mDragResult);
     }
 
@@ -365,8 +366,8 @@
     }
 
     /** @hide */
-    public IDropPermissions getDropPermissions() {
-        return mDropPermissions;
+    public IDragAndDropPermissions getDragAndDropPermissions() {
+        return mDragAndDropPermissions;
     }
 
     /**
@@ -489,11 +490,11 @@
             dest.writeInt(1);
             mClipDescription.writeToParcel(dest, flags);
         }
-        if (mDropPermissions == null) {
+        if (mDragAndDropPermissions == null) {
             dest.writeInt(0);
         } else {
             dest.writeInt(1);
-            dest.writeStrongBinder(mDropPermissions.asBinder());
+            dest.writeStrongBinder(mDragAndDropPermissions.asBinder());
         }
     }
 
@@ -515,7 +516,8 @@
                 event.mClipDescription = ClipDescription.CREATOR.createFromParcel(in);
             }
             if (in.readInt() != 0) {
-                event.mDropPermissions = IDropPermissions.Stub.asInterface(in.readStrongBinder());;
+                event.mDragAndDropPermissions =
+                        IDragAndDropPermissions.Stub.asInterface(in.readStrongBinder());;
             }
             return event;
         }
diff --git a/core/java/android/view/FrameMetrics.java b/core/java/android/view/FrameMetrics.java
index 8e66f86..5c4450a 100644
--- a/core/java/android/view/FrameMetrics.java
+++ b/core/java/android/view/FrameMetrics.java
@@ -234,7 +234,8 @@
      * Constructs a FrameMetrics object as a copy.
      * <p>
      * Use this method to copy out metrics reported by
-     * {@link Window.FrameMetricsListener#onMetricsAvailable(Window, FrameMetrics, int)}
+     * {@link Window.OnFrameMetricsAvailableListener#onFrameMetricsAvailable(
+     * Window, FrameMetrics, int)}
      * </p>
      * @param other the FrameMetrics object to copy.
      */
diff --git a/core/java/android/view/FrameMetricsObserver.java b/core/java/android/view/FrameMetricsObserver.java
index f38f8b7..6331357 100644
--- a/core/java/android/view/FrameMetricsObserver.java
+++ b/core/java/android/view/FrameMetricsObserver.java
@@ -40,7 +40,7 @@
 
     private FrameMetrics mFrameMetrics;
 
-    /* package */ Window.FrameMetricsListener mListener;
+    /* package */ Window.OnFrameMetricsAvailableListener mListener;
     /* package */ VirtualRefBasePtr mNative;
 
     /**
@@ -49,7 +49,7 @@
      * @param looper the looper to use when invoking callbacks
      */
     FrameMetricsObserver(@NonNull Window window, @NonNull Looper looper,
-            @NonNull Window.FrameMetricsListener listener) {
+            @NonNull Window.OnFrameMetricsAvailableListener listener) {
         if (looper == null) {
             throw new NullPointerException("looper cannot be null");
         }
@@ -69,7 +69,7 @@
     private void notifyDataAvailable(int dropCount) {
         final Window window = mWindow.get();
         if (window != null) {
-            mListener.onMetricsAvailable(window, mFrameMetrics, dropCount);
+            mListener.onFrameMetricsAvailable(window, mFrameMetrics, dropCount);
         }
     }
 }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 97af8f4..6e0175f 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -5513,7 +5513,8 @@
      *
      * @hide
      */
-    public void addFrameMetricsListener(Window window, Window.FrameMetricsListener listener,
+    public void addFrameMetricsListener(Window window,
+            Window.OnFrameMetricsAvailableListener listener,
             Handler handler) {
         if (mAttachInfo != null) {
             if (mAttachInfo.mHardwareRenderer != null) {
@@ -5544,11 +5545,13 @@
      *
      * @hide
      */
-    public void removeFrameMetricsListener(Window.FrameMetricsListener listener) {
+    public void removeFrameMetricsListener(
+            Window.OnFrameMetricsAvailableListener listener) {
         ThreadedRenderer renderer = getHardwareRenderer();
         FrameMetricsObserver fmo = findFrameMetricsObserver(listener);
         if (fmo == null) {
-            throw new IllegalArgumentException("attempt to remove FrameMetricsListener that was never added");
+            throw new IllegalArgumentException(
+                    "attempt to remove OnFrameMetricsAvailableListener that was never added");
         }
 
         if (mFrameMetricsObservers != null) {
@@ -5572,7 +5575,8 @@
         }
     }
 
-    private FrameMetricsObserver findFrameMetricsObserver(Window.FrameMetricsListener listener) {
+    private FrameMetricsObserver findFrameMetricsObserver(
+            Window.OnFrameMetricsAvailableListener listener) {
         for (int i = 0; i < mFrameMetricsObservers.size(); i++) {
             FrameMetricsObserver observer = mFrameMetricsObservers.get(i);
             if (observer.mListener == listener) {
@@ -20619,6 +20623,12 @@
         }
     }
 
+    /**
+     * Updates the drag shadow for the ongoing drag and drop operation.
+     *
+     * @param shadowBuilder A {@link android.view.View.DragShadowBuilder} object for building the
+     * new drag shadow.
+     */
     public final void updateDragShadow(DragShadowBuilder shadowBuilder) {
         if (ViewDebug.DEBUG_DRAG) {
             Log.d(VIEW_LOG_TAG, "updateDragShadow");
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 5135657..e3abb5d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -43,6 +43,8 @@
 import android.transition.TransitionManager;
 import android.view.accessibility.AccessibilityEvent;
 
+import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+
 import java.util.List;
 
 /**
@@ -610,7 +612,7 @@
      * Callback for clients that want frame timing information for each
      * frame rendered by the Window.
      */
-    public interface FrameMetricsListener {
+    public interface OnFrameMetricsAvailableListener {
         /**
          * Called when information is available for the previously rendered frame.
          *
@@ -629,7 +631,7 @@
          * @param dropCountSinceLastInvocation the number of reports dropped since the last time
          * this callback was invoked.
          */
-        void onMetricsAvailable(Window window, FrameMetrics frameMetrics,
+        void onFrameMetricsAvailable(Window window, FrameMetrics frameMetrics,
                 int dropCountSinceLastInvocation);
     }
 
@@ -792,8 +794,9 @@
         if (wp.packageName == null) {
             wp.packageName = mContext.getPackageName();
         }
-        if (mHardwareAccelerated) {
-            wp.flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+        if (mHardwareAccelerated ||
+                (mWindowAttributes.flags & FLAG_HARDWARE_ACCELERATED) != 0) {
+            wp.flags |= FLAG_HARDWARE_ACCELERATED;
         }
     }
 
@@ -829,7 +832,8 @@
      *
      * Must be in hardware rendering mode.
      */
-    public final void addFrameMetricsListener(@NonNull FrameMetricsListener listener,
+    public final void addOnFrameMetricsAvailableListener(
+            @NonNull OnFrameMetricsAvailableListener listener,
             Handler handler) {
         final View decorView = getDecorView();
         if (decorView == null) {
@@ -846,7 +850,7 @@
     /**
      * Remove observer and stop listening to frame stats for this window.
      */
-    public final void removeFrameMetricsListener(FrameMetricsListener listener) {
+    public final void removeOnFrameMetricsAvailableListener(OnFrameMetricsAvailableListener listener) {
         final View decorView = getDecorView();
         if (decorView != null) {
             getDecorView().removeFrameMetricsListener(listener);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 54e9942..9b74fc0 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1251,7 +1251,7 @@
          * the device supports it.
          * @hide
          */
-        public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00020000;
+        public static final int PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE = 0x00040000;
 
         /**
          * Control flags that are private to the platform.
diff --git a/core/java/android/webkit/WebViewDelegate.java b/core/java/android/webkit/WebViewDelegate.java
index 2b54875..85d7cd0 100644
--- a/core/java/android/webkit/WebViewDelegate.java
+++ b/core/java/android/webkit/WebViewDelegate.java
@@ -74,9 +74,7 @@
      * and false otherwise.
      */
     public boolean canInvokeDrawGlFunctor(View containerView) {
-        ViewRootImpl viewRootImpl = containerView.getViewRootImpl();
-         // viewRootImpl can be null during teardown when window is leaked.
-        return viewRootImpl != null;
+        return true;
     }
 
     /**
diff --git a/core/java/android/webkit/WebViewFragment.java b/core/java/android/webkit/WebViewFragment.java
index 852878b..d803f62d 100644
--- a/core/java/android/webkit/WebViewFragment.java
+++ b/core/java/android/webkit/WebViewFragment.java
@@ -44,7 +44,7 @@
         if (mWebView != null) {
             mWebView.destroy();
         }
-        mWebView = new WebView(getActivity());
+        mWebView = new WebView(getContext());
         mIsWebViewAvailable = true;
         return mWebView;
     }
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index a12b15e..1a1680a 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -16,6 +16,7 @@
 */
 package android.widget;
 
+import android.annotation.SystemApi;
 import android.os.UserHandle;
 import com.android.internal.R;
 
@@ -80,6 +81,7 @@
     private final CharSequence mNewPermPrefix;
     private String mPackageName;
 
+    /** @hide */
     static class MyPermissionGroupInfo extends PermissionGroupInfo {
         CharSequence mLabel;
 
@@ -104,6 +106,7 @@
         }
     }
 
+    /** @hide */
     private static class MyPermissionInfo extends PermissionInfo {
         CharSequence mLabel;
 
@@ -128,6 +131,7 @@
         }
     }
 
+    /** @hide */
     public static class PermissionItemView extends LinearLayout implements View.OnClickListener {
         MyPermissionGroupInfo mGroup;
         MyPermissionInfo mPerm;
diff --git a/core/java/android/widget/DateTimeView.java b/core/java/android/widget/DateTimeView.java
index d20b924..d2ee866 100644
--- a/core/java/android/widget/DateTimeView.java
+++ b/core/java/android/widget/DateTimeView.java
@@ -16,21 +16,32 @@
 
 package android.widget;
 
+import static android.text.format.DateUtils.DAY_IN_MILLIS;
+import static android.text.format.DateUtils.HOUR_IN_MILLIS;
+import static android.text.format.DateUtils.MINUTE_IN_MILLIS;
+import static android.text.format.DateUtils.YEAR_IN_MILLIS;
+import static android.text.format.Time.getJulianDay;
+
 import android.app.ActivityThread;
+import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
-import android.content.BroadcastReceiver;
+import android.content.res.Configuration;
+import android.content.res.TypedArray;
 import android.database.ContentObserver;
+import android.icu.util.Calendar;
 import android.os.Handler;
 import android.text.format.Time;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.widget.RemoteViews.RemoteView;
 
+import com.android.internal.R;
+
 import java.text.DateFormat;
 import java.util.ArrayList;
 import java.util.Date;
+import java.util.TimeZone;
 
 //
 // TODO
@@ -46,11 +57,6 @@
  */
 @RemoteView
 public class DateTimeView extends TextView {
-    private static final String TAG = "DateTimeView";
-
-    private static final long TWELVE_HOURS_IN_MINUTES = 12 * 60;
-    private static final long TWENTY_FOUR_HOURS_IN_MILLIS = 24 * 60 * 60 * 1000;
-
     private static final int SHOW_TIME = 0;
     private static final int SHOW_MONTH_DAY_YEAR = 1;
 
@@ -62,13 +68,30 @@
 
     private long mUpdateTimeMillis;
     private static final ThreadLocal<ReceiverInfo> sReceiverInfo = new ThreadLocal<ReceiverInfo>();
+    private String mNowText;
+    private boolean mShowRelativeTime;
 
     public DateTimeView(Context context) {
-        super(context);
+        this(context, null);
     }
 
     public DateTimeView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        final TypedArray a = context.obtainStyledAttributes(attrs,
+                com.android.internal.R.styleable.DateTimeView, 0,
+                0);
+
+        final int N = a.getIndexCount();
+        for (int i = 0; i < N; i++) {
+            int attr = a.getIndex(i);
+            switch (attr) {
+                case R.styleable.DateTimeView_showRelative:
+                    boolean relative = a.getBoolean(i, false);
+                    setShowRelativeTime(relative);
+                    break;
+            }
+        }
+        a.recycle();
     }
 
     @Override
@@ -101,12 +124,31 @@
         update();
     }
 
+    @android.view.RemotableViewMethod
+    public void setShowRelativeTime(boolean showRelativeTime) {
+        mShowRelativeTime = showRelativeTime;
+        updateNowText();
+        update();
+    }
+
+    @Override
+    @android.view.RemotableViewMethod
+    public void setVisibility(@Visibility int visibility) {
+        boolean gotVisible = visibility != GONE && getVisibility() == GONE;
+        super.setVisibility(visibility);
+        if (gotVisible) {
+            update();
+        }
+    }
+
     void update() {
-        if (mTime == null) {
+        if (mTime == null || getVisibility() == GONE) {
             return;
         }
-
-        long start = System.nanoTime();
+        if (mShowRelativeTime) {
+            updateRelativeTime();
+            return;
+        }
 
         int display;
         Date time = mTime;
@@ -181,12 +223,105 @@
                         ? twelveHoursBefore : midnightBefore;
             }
         }
-        if (false) {
-            Log.d(TAG, "update needed for '" + time + "' at '" + new Date(mUpdateTimeMillis)
-                    + "' - text=" + text);
-        }
+    }
 
-        long finish = System.nanoTime();
+    private void updateRelativeTime() {
+        long now = System.currentTimeMillis();
+        long duration = Math.abs(now - mTimeMillis);
+        int count;
+        long millisIncrease;
+        boolean past = (now >= mTimeMillis);
+        String result;
+        if (duration < MINUTE_IN_MILLIS) {
+            setText(mNowText);
+            mUpdateTimeMillis = mTimeMillis + MINUTE_IN_MILLIS + 1;
+            return;
+        } else if (duration < HOUR_IN_MILLIS) {
+            count = (int)(duration / MINUTE_IN_MILLIS);
+            result = String.format(getContext().getResources().getQuantityString(past
+                            ? com.android.internal.R.plurals.duration_minutes_shortest
+                            : com.android.internal.R.plurals.duration_minutes_shortest_future,
+                            count),
+                    count);
+            millisIncrease = MINUTE_IN_MILLIS;
+        } else if (duration < DAY_IN_MILLIS) {
+            count = (int)(duration / HOUR_IN_MILLIS);
+            result = String.format(getContext().getResources().getQuantityString(past
+                            ? com.android.internal.R.plurals.duration_hours_shortest
+                            : com.android.internal.R.plurals.duration_hours_shortest_future,
+                            count),
+                    count);
+            millisIncrease = HOUR_IN_MILLIS;
+        } else if (duration < YEAR_IN_MILLIS) {
+            // In weird cases it can become 0 because of daylight savings
+            TimeZone timeZone = TimeZone.getDefault();
+            count = Math.max(Math.abs(dayDistance(timeZone, mTimeMillis, now)), 1);
+            result = String.format(getContext().getResources().getQuantityString(past
+                            ? com.android.internal.R.plurals.duration_days_shortest
+                            : com.android.internal.R.plurals.duration_days_shortest_future,
+                            count),
+                    count);
+            if (past || count != 1) {
+                mUpdateTimeMillis = computeNextMidnight(timeZone);
+                millisIncrease = -1;
+            } else {
+                millisIncrease = DAY_IN_MILLIS;
+            }
+
+        } else {
+            count = (int)(duration / YEAR_IN_MILLIS);
+            result = String.format(getContext().getResources().getQuantityString(past
+                            ? com.android.internal.R.plurals.duration_years_shortest
+                            : com.android.internal.R.plurals.duration_years_shortest_future,
+                            count),
+                    count);
+            millisIncrease = YEAR_IN_MILLIS;
+        }
+        if (millisIncrease != -1) {
+            if (past) {
+                mUpdateTimeMillis = mTimeMillis + millisIncrease * (count + 1) + 1;
+            } else {
+                mUpdateTimeMillis = mTimeMillis - millisIncrease * count + 1;
+            }
+        }
+        setText(result);
+    }
+
+    /**
+     * @param timeZone the timezone we are in
+     * @return the timepoint in millis at UTC at midnight in the current timezone
+     */
+    private long computeNextMidnight(TimeZone timeZone) {
+        Calendar c = Calendar.getInstance();
+        c.setTimeZone(libcore.icu.DateUtilsBridge.icuTimeZone(timeZone));
+        c.add(Calendar.DAY_OF_MONTH, 1);
+        c.set(Calendar.HOUR_OF_DAY, 0);
+        c.set(Calendar.MINUTE, 0);
+        c.set(Calendar.SECOND, 0);
+        c.set(Calendar.MILLISECOND, 0);
+        return c.getTimeInMillis();
+    }
+
+    @Override
+    protected void onConfigurationChanged(Configuration newConfig) {
+        super.onConfigurationChanged(newConfig);
+        updateNowText();
+        update();
+    }
+
+    private void updateNowText() {
+        if (!mShowRelativeTime) {
+            return;
+        }
+        mNowText = getContext().getResources().getString(
+                com.android.internal.R.string.now_string_shortest);
+    }
+
+    // Return the date difference for the two times in a given timezone.
+    private static int dayDistance(TimeZone timeZone, long startTime,
+            long endTime) {
+        return getJulianDay(endTime, timeZone.getOffset(endTime) / 1000)
+                - getJulianDay(startTime, timeZone.getOffset(startTime) / 1000);
     }
 
     private DateFormat getTimeFormat() {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 440ef21..5d2683f 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -77,8 +77,8 @@
 import android.view.ActionMode.Callback;
 import android.view.ContextMenu;
 import android.view.DisplayListCanvas;
+import android.view.DragAndDropPermissions;
 import android.view.DragEvent;
-import android.view.DropPermissions;
 import android.view.Gravity;
 import android.view.InputDevice;
 import android.view.LayoutInflater;
@@ -2379,9 +2379,9 @@
     void onDrop(DragEvent event) {
         StringBuilder content = new StringBuilder("");
 
-        final DropPermissions dropPermissions = DropPermissions.obtain(event);
-        if (dropPermissions != null) {
-            dropPermissions.takeTransient();
+        final DragAndDropPermissions permissions = DragAndDropPermissions.obtain(event);
+        if (permissions != null) {
+            permissions.takeTransient();
         }
 
         try {
@@ -2393,8 +2393,8 @@
             }
         }
         finally {
-            if (dropPermissions != null) {
-                dropPermissions.release();
+            if (permissions != null) {
+                permissions.release();
             }
         }
 
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index 9c9784b..3c967ac 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1397,6 +1397,10 @@
     /**
      * Sets the current progress to the specified value. Does not do anything
      * if the progress bar is in indeterminate mode.
+     * <p>
+     * This method will immediately update the visual position of the progress
+     * indicator. To animate the visual position to the target value, use
+     * {@link #setProgress(int, boolean)}}.
      *
      * @param progress the new progress, between 0 and {@link #getMax()}
      *
@@ -1412,7 +1416,7 @@
 
     /**
      * Sets the current progress to the specified value, optionally animating
-     * between the current and target values.
+     * the visual position between the current and target values.
      * <p>
      * Animation does not affect the result of {@link #getProgress()}, which
      * will return the target value immediately after this method is called.
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index a9b7f4e..6dc5ff7 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -2600,7 +2600,7 @@
      *               simply display the timer value.
      * @param started True if you want the clock to be started, false if not.
      *
-     * @see #setChronometerCountsDown(int, boolean)
+     * @see #setChronometerCountDown(int, boolean)
      */
     public void setChronometer(int viewId, long base, String format, boolean started) {
         setLong(viewId, "setBase", base);
@@ -2616,7 +2616,7 @@
      * @param isCountDown True if you want the chronometer to count down to base instead of
      *                    counting up.
      */
-    public void setChronometerCountsDown(int viewId, boolean isCountDown) {
+    public void setChronometerCountDown(int viewId, boolean isCountDown) {
         setBoolean(viewId, "setCountDown", isCountDown);
     }
 
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 8097d7a..3216fba 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1591,6 +1591,7 @@
         }
     }
 
+    @android.view.RemotableViewMethod
     @Override
     public void setEnabled(boolean enabled) {
         if (enabled == isEnabled()) {
diff --git a/core/java/com/android/internal/app/LocaleStore.java b/core/java/com/android/internal/app/LocaleStore.java
index 7803e52..e3fce51 100644
--- a/core/java/com/android/internal/app/LocaleStore.java
+++ b/core/java/com/android/internal/app/LocaleStore.java
@@ -126,12 +126,18 @@
             return mFullCountryNameNative;
         }
 
+        String getFullCountryNameInUiLanguage() {
+            // We don't cache the UI name because the default locale keeps changing
+            return LocaleHelper.getDisplayCountry(mLocale);
+        }
+
         /** Returns the name of the locale in the language of the UI.
          * It is used for search, but never shown.
          * For instance German will show as "Deutsch" in the list, but we will also search for
          * "allemand" if the system UI is in French.
          */
         public String getFullNameInUiLanguage() {
+            // We don't cache the UI name because the default locale keeps changing
             return LocaleHelper.getDisplayName(mLocale, true /* sentence case */);
         }
 
@@ -154,6 +160,14 @@
             }
         }
 
+        String getContentDescription(boolean countryMode) {
+            if (countryMode) {
+                return getFullCountryNameInUiLanguage();
+            } else {
+                return getFullNameInUiLanguage();
+            }
+        }
+
         public boolean getChecked() {
             return mIsChecked;
         }
diff --git a/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java b/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
index 108e81f..466c015 100644
--- a/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
+++ b/core/java/com/android/internal/app/MediaRouteControllerDialogFragment.java
@@ -55,6 +55,6 @@
 
     @Override
     public Dialog onCreateDialog(Bundle savedInstanceState) {
-        return onCreateControllerDialog(getActivity(), savedInstanceState);
+        return onCreateControllerDialog(getContext(), savedInstanceState);
     }
 }
diff --git a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
index e2d29e3..a4b5a8e 100644
--- a/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
+++ b/core/java/com/android/internal/app/SuggestedLocaleAdapter.java
@@ -159,6 +159,7 @@
                 LocaleStore.LocaleInfo item = (LocaleStore.LocaleInfo) getItem(position);
                 text.setText(item.getLabel(mCountryMode));
                 text.setTextLocale(item.getLocale());
+                text.setContentDescription(item.getContentDescription(mCountryMode));
                 if (mCountryMode) {
                     int layoutDir = TextUtils.getLayoutDirectionFromLocale(item.getParent());
                     //noinspection ResourceType
diff --git a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
index 975021e8..04d7f9b 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodSubtypeHandle.java
@@ -16,6 +16,7 @@
 
 package com.android.internal.inputmethod;
 
+import android.annotation.Nullable;
 import android.text.TextUtils;
 import android.view.inputmethod.InputMethodInfo;
 import android.view.inputmethod.InputMethodSubtype;
@@ -26,12 +27,12 @@
     private final String mInputMethodId;
     private final int mSubtypeId;
 
-    public InputMethodSubtypeHandle(InputMethodInfo info, InputMethodSubtype subtype) {
+    public InputMethodSubtypeHandle(InputMethodInfo info, @Nullable InputMethodSubtype subtype) {
         mInputMethodId = info.getId();
         if (subtype != null) {
             mSubtypeId = subtype.hashCode();
         } else {
-            mSubtypeId = 0;
+            mSubtypeId = InputMethodUtils.NOT_A_SUBTYPE_ID;
         }
     }
 
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 1b52146..27ffb8b 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -94,14 +94,14 @@
 
     private int mStatsType = BatteryStats.STATS_SINCE_CHARGED;
 
-    long mRawRealtime;
-    long mRawUptime;
-    long mBatteryRealtime;
-    long mBatteryUptime;
-    long mTypeBatteryRealtime;
-    long mTypeBatteryUptime;
-    long mBatteryTimeRemaining;
-    long mChargeTimeRemaining;
+    long mRawRealtimeUs;
+    long mRawUptimeUs;
+    long mBatteryRealtimeUs;
+    long mBatteryUptimeUs;
+    long mTypeBatteryRealtimeUs;
+    long mTypeBatteryUptimeUs;
+    long mBatteryTimeRemainingUs;
+    long mChargeTimeRemainingUs;
 
     private long mStatsPeriod = 0;
 
@@ -389,22 +389,22 @@
         mFlashlightPowerCalculator.reset();
 
         mStatsType = statsType;
-        mRawUptime = rawUptimeUs;
-        mRawRealtime = rawRealtimeUs;
-        mBatteryUptime = mStats.getBatteryUptime(rawUptimeUs);
-        mBatteryRealtime = mStats.getBatteryRealtime(rawRealtimeUs);
-        mTypeBatteryUptime = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
-        mTypeBatteryRealtime = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
-        mBatteryTimeRemaining = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
-        mChargeTimeRemaining = mStats.computeChargeTimeRemaining(rawRealtimeUs);
+        mRawUptimeUs = rawUptimeUs;
+        mRawRealtimeUs = rawRealtimeUs;
+        mBatteryUptimeUs = mStats.getBatteryUptime(rawUptimeUs);
+        mBatteryRealtimeUs = mStats.getBatteryRealtime(rawRealtimeUs);
+        mTypeBatteryUptimeUs = mStats.computeBatteryUptime(rawUptimeUs, mStatsType);
+        mTypeBatteryRealtimeUs = mStats.computeBatteryRealtime(rawRealtimeUs, mStatsType);
+        mBatteryTimeRemainingUs = mStats.computeBatteryTimeRemaining(rawRealtimeUs);
+        mChargeTimeRemainingUs = mStats.computeChargeTimeRemaining(rawRealtimeUs);
 
         if (DEBUG) {
             Log.d(TAG, "Raw time: realtime=" + (rawRealtimeUs/1000) + " uptime="
                     + (rawUptimeUs/1000));
-            Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtime/1000) + " uptime="
-                    + (mBatteryUptime/1000));
-            Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtime/1000) + " uptime="
-                    + (mTypeBatteryUptime/1000));
+            Log.d(TAG, "Battery time: realtime=" + (mBatteryRealtimeUs /1000) + " uptime="
+                    + (mBatteryUptimeUs /1000));
+            Log.d(TAG, "Battery type time: realtime=" + (mTypeBatteryRealtimeUs /1000) + " uptime="
+                    + (mTypeBatteryUptimeUs /1000));
         }
         mMinDrainedPower = (mStats.getLowDischargeAmountSinceCharge()
                 * mPowerProfile.getBatteryCapacity()) / 100;
@@ -489,7 +489,7 @@
 
     private void processAppUsage(SparseArray<UserHandle> asUsers) {
         final boolean forAllUsers = (asUsers.get(UserHandle.USER_ALL) != null);
-        mStatsPeriod = mTypeBatteryRealtime;
+        mStatsPeriod = mTypeBatteryRealtimeUs;
 
         BatterySipper osSipper = null;
         final SparseArray<? extends Uid> uidStats = mStats.getUidStats();
@@ -498,14 +498,14 @@
             final Uid u = uidStats.valueAt(iu);
             final BatterySipper app = new BatterySipper(BatterySipper.DrainType.APP, u, 0);
 
-            mCpuPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mWifiPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mSensorPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mCameraPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
-            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtime, mRawUptime, mStatsType);
+            mCpuPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mWakelockPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mMobileRadioPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mWifiPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mBluetoothPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mSensorPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mCameraPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
+            mFlashlightPowerCalculator.calculateApp(app, u, mRawRealtimeUs, mRawUptimeUs, mStatsType);
 
             final double totalPower = app.sumPower();
             if (DEBUG && totalPower != 0) {
@@ -547,14 +547,14 @@
             // The device has probably been awake for longer than the screen on
             // time and application wake lock time would account for.  Assign
             // this remainder to the OS, if possible.
-            mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtime,
-                                                        mRawUptime, mStatsType);
+            mWakelockPowerCalculator.calculateRemaining(osSipper, mStats, mRawRealtimeUs,
+                    mRawUptimeUs, mStatsType);
             osSipper.sumPower();
         }
     }
 
     private void addPhoneUsage() {
-        long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtime, mStatsType) / 1000;
+        long phoneOnTimeMs = mStats.getPhoneOnTime(mRawRealtimeUs, mStatsType) / 1000;
         double phoneOnPower = mPowerProfile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE)
                 * phoneOnTimeMs / (60*60*1000);
         if (phoneOnPower != 0) {
@@ -562,16 +562,19 @@
         }
     }
 
+    /**
+     * Screen power is the additional power the screen takes while the device is running.
+     */
     private void addScreenUsage() {
         double power = 0;
-        long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtime, mStatsType) / 1000;
+        long screenOnTimeMs = mStats.getScreenOnTime(mRawRealtimeUs, mStatsType) / 1000;
         power += screenOnTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_ON);
         final double screenFullPower =
                 mPowerProfile.getAveragePower(PowerProfile.POWER_SCREEN_FULL);
         for (int i = 0; i < BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS; i++) {
             double screenBinPower = screenFullPower * (i + 0.5f)
                     / BatteryStats.NUM_SCREEN_BRIGHTNESS_BINS;
-            long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtime, mStatsType)
+            long brightnessTime = mStats.getScreenBrightnessTime(i, mRawRealtimeUs, mStatsType)
                     / 1000;
             double p = screenBinPower*brightnessTime;
             if (DEBUG && p != 0) {
@@ -588,7 +591,7 @@
 
     private void addRadioUsage() {
         BatterySipper radio = new BatterySipper(BatterySipper.DrainType.CELL, null, 0);
-        mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtime, mRawUptime,
+        mMobileRadioPowerCalculator.calculateRemaining(radio, mStats, mRawRealtimeUs, mRawUptimeUs,
                 mStatsType);
         radio.sumPower();
         if (radio.totalPowerMah > 0) {
@@ -606,16 +609,26 @@
         bs.sumPower();
     }
 
+    /**
+     * Calculate the baseline power usage for the device when it is in suspend and idle.
+     * The device is drawing POWER_CPU_IDLE power at its lowest power state.
+     * The device is drawing POWER_CPU_IDLE + POWER_CPU_AWAKE power when a wakelock is held.
+     */
     private void addIdleUsage() {
-        long idleTimeMs = (mTypeBatteryRealtime
-                - mStats.getScreenOnTime(mRawRealtime, mStatsType)) / 1000;
-        double idlePower = (idleTimeMs * mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE))
-                / (60*60*1000);
-        if (DEBUG && idlePower != 0) {
-            Log.d(TAG, "Idle: time=" + idleTimeMs + " power=" + makemAh(idlePower));
+        final double suspendPowerMaMs = (mTypeBatteryRealtimeUs / 1000) *
+                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_IDLE);
+        final double idlePowerMaMs = (mTypeBatteryUptimeUs / 1000) *
+                mPowerProfile.getAveragePower(PowerProfile.POWER_CPU_AWAKE);
+        final double totalPowerMah = (suspendPowerMaMs + idlePowerMaMs) / (60 * 60 * 1000);
+        if (DEBUG && totalPowerMah != 0) {
+            Log.d(TAG, "Suspend: time=" + (mTypeBatteryRealtimeUs / 1000)
+                    + " power=" + makemAh(suspendPowerMaMs / (60 * 60 * 1000)));
+            Log.d(TAG, "Idle: time=" + (mTypeBatteryUptimeUs / 1000)
+                    + " power=" + makemAh(idlePowerMaMs / (60 * 60 * 1000)));
         }
-        if (idlePower != 0) {
-            addEntry(BatterySipper.DrainType.IDLE, idleTimeMs, idlePower);
+
+        if (totalPowerMah != 0) {
+            addEntry(BatterySipper.DrainType.IDLE, mTypeBatteryRealtimeUs / 1000, totalPowerMah);
         }
     }
 
@@ -628,7 +641,7 @@
      */
     private void addWiFiUsage() {
         BatterySipper bs = new BatterySipper(DrainType.WIFI, null, 0);
-        mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime, mStatsType);
+        mWifiPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs, mStatsType);
         aggregateSippers(bs, mWifiSippers, "WIFI");
         if (bs.totalPowerMah > 0) {
             mUsageList.add(bs);
@@ -641,7 +654,7 @@
      */
     private void addBluetoothUsage() {
         BatterySipper bs = new BatterySipper(BatterySipper.DrainType.BLUETOOTH, null, 0);
-        mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtime, mRawUptime,
+        mBluetoothPowerCalculator.calculateRemaining(bs, mStats, mRawRealtimeUs, mRawUptimeUs,
                 mStatsType);
         aggregateSippers(bs, mBluetoothSippers, "Bluetooth");
         if (bs.totalPowerMah > 0) {
@@ -709,10 +722,6 @@
         return mMaxDrainedPower;
     }
 
-    public long getBatteryTimeRemaining() { return mBatteryTimeRemaining; }
-
-    public long getChargeTimeRemaining() { return mChargeTimeRemaining; }
-
     public static byte[] readFully(FileInputStream stream) throws java.io.IOException {
         return readFully(stream, stream.available());
     }
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 250d9b7..8d7dc35 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -3400,7 +3400,7 @@
                     powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_MEDIUM
                             || powerState == DataConnectionRealTimeInfo.DC_POWER_STATE_HIGH;
             if (active) {
-                mMobileRadioActiveStartTime = realElapsedRealtimeMs = elapsedRealtime;
+                mMobileRadioActiveStartTime = realElapsedRealtimeMs = timestampNs / (1000 * 1000);
                 mHistoryCur.states |= HistoryItem.STATE_MOBILE_RADIO_ACTIVE_FLAG;
             } else {
                 realElapsedRealtimeMs = timestampNs / (1000*1000);
diff --git a/core/java/com/android/internal/os/BinderInternal.java b/core/java/com/android/internal/os/BinderInternal.java
index d77b998..ea4575a 100644
--- a/core/java/com/android/internal/os/BinderInternal.java
+++ b/core/java/com/android/internal/os/BinderInternal.java
@@ -93,6 +93,8 @@
      * @hide
      */
     public static final native void disableBackgroundScheduling(boolean disable);
+
+    public static final native void setMaxThreads(int numThreads);
     
     static native final void handleGc();
     
diff --git a/core/java/com/android/internal/os/PowerProfile.java b/core/java/com/android/internal/os/PowerProfile.java
index 79138b7..d217474 100644
--- a/core/java/com/android/internal/os/PowerProfile.java
+++ b/core/java/com/android/internal/os/PowerProfile.java
@@ -51,7 +51,7 @@
      * Power consumption when CPU is awake (when a wake lock is held).  This
      * should be 0 on devices that can go into full CPU power collapse even
      * when a wake lock is held.  Otherwise, this is the power consumption in
-     * addition to POWERR_CPU_IDLE due to a wake lock being held but with no
+     * addition to POWER_CPU_IDLE due to a wake lock being held but with no
      * CPU activity.
      */
     public static final String POWER_CPU_AWAKE = "cpu.awake";
diff --git a/core/java/com/android/internal/statusbar/IStatusBar.aidl b/core/java/com/android/internal/statusbar/IStatusBar.aidl
index fcf65f2..5cbe1ce 100644
--- a/core/java/com/android/internal/statusbar/IStatusBar.aidl
+++ b/core/java/com/android/internal/statusbar/IStatusBar.aidl
@@ -65,6 +65,7 @@
     void cancelPreloadRecentApps();
     void showScreenPinningRequest(int taskId);
 
+    void dismissKeyboardShortcutsMenu();
     void toggleKeyboardShortcutsMenu(int deviceId);
 
     /**
diff --git a/core/java/com/android/internal/view/IDropPermissions.aidl b/core/java/com/android/internal/view/IDragAndDropPermissions.aidl
similarity index 96%
rename from core/java/com/android/internal/view/IDropPermissions.aidl
rename to core/java/com/android/internal/view/IDragAndDropPermissions.aidl
index 74ff4b4..64c2d04 100644
--- a/core/java/com/android/internal/view/IDropPermissions.aidl
+++ b/core/java/com/android/internal/view/IDragAndDropPermissions.aidl
@@ -22,7 +22,7 @@
  * Interface to allow a drop receiver to request permissions for URIs passed along with ClipData
  * contained in DragEvent.
  */
-interface IDropPermissions {
+interface IDragAndDropPermissions {
     void take(IBinder activityToken);
     void takeTransient(IBinder permissionOwnerToken);
     void release();
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index 5cb307f..72ed9d0 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -181,8 +181,10 @@
     private View mAnchorView;
     private View mShownAnchorView;
     private int mLastPosition;
-    private int mInitXOffset;
-    private int mInitYOffset;
+    private boolean mHasXOffset;
+    private boolean mHasYOffset;
+    private int mXOffset;
+    private int mYOffset;
     private boolean mForceShowIcon;
     private boolean mShowTitle;
     private Callback mPresenterCallback;
@@ -379,9 +381,6 @@
             parentView = null;
         }
 
-        final int x;
-        final int y;
-        final Rect epicenterBounds;
         if (parentView != null) {
             // This menu is a cascading submenu anchored to a parent view.
             popupWindow.setTouchModal(false);
@@ -401,6 +400,7 @@
 
             // By now, mDropDownGravity is the resolved absolute gravity, so
             // this should work in both LTR and RTL.
+            final int x;
             if ((mDropDownGravity & Gravity.RIGHT) == Gravity.RIGHT) {
                 if (showOnRight) {
                     x = parentOffsetLeft + menuWidth;
@@ -415,17 +415,21 @@
                 }
             }
 
-            y = parentOffsetTop;
-            epicenterBounds = null;
+            popupWindow.setHorizontalOffset(x);
+
+            final int y = parentOffsetTop;
+            popupWindow.setVerticalOffset(y);
         } else {
-            x = mInitXOffset;
-            y = mInitYOffset;
-            epicenterBounds = getEpicenterBounds();
+            if (mHasXOffset) {
+                popupWindow.setHorizontalOffset(mXOffset);
+            }
+            if (mHasYOffset) {
+                popupWindow.setVerticalOffset(mYOffset);
+            }
+            final Rect epicenterBounds = getEpicenterBounds();
+            popupWindow.setEpicenterBounds(epicenterBounds);
         }
 
-        popupWindow.setHorizontalOffset(x);
-        popupWindow.setVerticalOffset(y);
-        popupWindow.setEpicenterBounds(epicenterBounds);
 
         final CascadingMenuInfo menuInfo = new CascadingMenuInfo(popupWindow, menu, mLastPosition);
         mShowingMenus.add(menuInfo);
@@ -712,12 +716,14 @@
 
     @Override
     public void setHorizontalOffset(int x) {
-        mInitXOffset = x;
+        mHasXOffset = true;
+        mXOffset = x;
     }
 
     @Override
     public void setVerticalOffset(int y) {
-        mInitYOffset = y;
+        mHasYOffset = true;
+        mYOffset = y;
     }
 
     @Override
diff --git a/core/java/com/android/internal/view/menu/StandardMenuPopup.java b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
index 339c2bf..169caa5 100644
--- a/core/java/com/android/internal/view/menu/StandardMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/StandardMenuPopup.java
@@ -108,8 +108,6 @@
 
     private int mDropDownGravity = Gravity.NO_GRAVITY;
 
-    private int mXOffset;
-    private int mYOffset;
     private boolean mShowTitle;
 
     public StandardMenuPopup(Context context, MenuBuilder menu, View anchorView, int popupStyleAttr,
@@ -177,8 +175,6 @@
 
         mPopup.setContentWidth(mContentWidth);
         mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
-        mPopup.setHorizontalOffset(mXOffset);
-        mPopup.setVerticalOffset(mYOffset);
         mPopup.setEpicenterBounds(getEpicenterBounds());
         mPopup.show();
 
@@ -276,7 +272,9 @@
             mMenu.close(false /* closeAllMenus */);
 
             // Show the new sub-menu popup at the same location as this popup.
-            if (subPopup.tryShow(mXOffset, mYOffset)) {
+            final int horizontalOffset = mPopup.getHorizontalOffset();
+            final int verticalOffset = mPopup.getVerticalOffset();
+            if (subPopup.tryShow(horizontalOffset, verticalOffset)) {
                 if (mPresenterCallback != null) {
                     mPresenterCallback.onOpenSubMenu(subMenu);
                 }
@@ -338,12 +336,12 @@
 
     @Override
     public void setHorizontalOffset(int x) {
-        mXOffset = x;
+        mPopup.setHorizontalOffset(x);
     }
 
     @Override
     public void setVerticalOffset(int y) {
-        mYOffset = y;
+        mPopup.setVerticalOffset(y);
     }
 
     @Override
diff --git a/core/java/com/android/server/backup/SystemBackupAgent.java b/core/java/com/android/server/backup/SystemBackupAgent.java
index 2d12fcd..9d296fa 100644
--- a/core/java/com/android/server/backup/SystemBackupAgent.java
+++ b/core/java/com/android/server/backup/SystemBackupAgent.java
@@ -76,26 +76,6 @@
     @Override
     public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
             ParcelFileDescriptor newState) throws IOException {
-        // We only back up the data under the current "wallpaper" schema with metadata
-        IWallpaperManager wallpaper = (IWallpaperManager)ServiceManager.getService(
-                Context.WALLPAPER_SERVICE);
-        String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
-        String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
-        if (wallpaper != null) {
-            try {
-                final String wallpaperName = wallpaper.getName();
-                if (wallpaperName != null && wallpaperName.length() > 0) {
-                    // When the wallpaper has a name, back up the info by itself.
-                    // TODO: Don't rely on the innards of the service object like this!
-                    // TODO: Send a delete for any stored wallpaper image in this case?
-                    files = new String[] { WALLPAPER_INFO };
-                    keys = new String[] { WALLPAPER_INFO_KEY };
-                }
-            } catch (RemoteException re) {
-                Slog.e(TAG, "Couldn't get wallpaper name\n" + re);
-            }
-        }
-        addHelper(WALLPAPER_HELPER, new WallpaperBackupHelper(this, files, keys));
         addHelper(SYNC_SETTINGS_HELPER, new AccountSyncSettingsBackupHelper(this));
         addHelper(PREFERRED_HELPER, new PreferredActivityBackupHelper());
         addHelper(NOTIFICATION_HELPER, new NotificationBackupHelper(this));
@@ -107,30 +87,20 @@
 
     @Override
     public void onFullBackup(FullBackupDataOutput data) throws IOException {
-        // At present we back up only the wallpaper
-        fullWallpaperBackup(data);
-    }
-
-    private void fullWallpaperBackup(FullBackupDataOutput output) {
-        // Back up the data files directly.  We do them in this specific order --
-        // info file followed by image -- because then we need take no special
-        // steps during restore; the restore will happen properly when the individual
-        // files are restored piecemeal.
-        FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
-                WALLPAPER_INFO_DIR, WALLPAPER_INFO, output);
-        FullBackup.backupToTar(getPackageName(), FullBackup.ROOT_TREE_TOKEN, null,
-                WALLPAPER_IMAGE_DIR, WALLPAPER_IMAGE, output);
+        // At present we don't back up anything
     }
 
     @Override
     public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
             throws IOException {
+        // Slot in a restore helper for the older wallpaper backup schema to support restore
+        // from devices still generating data in that format.
         mWallpaperHelper = new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
                 new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} );
         addHelper(WALLPAPER_HELPER, mWallpaperHelper);
 
-        // On restore, we also support a previous data schema "system_files"
+        // On restore, we also support a long-ago wallpaper data schema "system_files"
         addHelper("system_files", new WallpaperBackupHelper(this,
                 new String[] { WALLPAPER_IMAGE },
                 new String[] { WALLPAPER_IMAGE_KEY} ));
@@ -213,6 +183,9 @@
 
     @Override
     public void onRestoreFinished() {
-        mWallpaperHelper.onRestoreFinished();
+        // helper will be null following 'adb restore' or other full-data operation
+        if (mWallpaperHelper != null) {
+            mWallpaperHelper.onRestoreFinished();
+        }
     }
 }
diff --git a/core/jni/android_util_Binder.cpp b/core/jni/android_util_Binder.cpp
index abc6c4b..5559d48 100644
--- a/core/jni/android_util_Binder.cpp
+++ b/core/jni/android_util_Binder.cpp
@@ -917,6 +917,12 @@
     IPCThreadState::disableBackgroundScheduling(disable ? true : false);
 }
 
+static void android_os_BinderInternal_setMaxThreads(JNIEnv* env,
+        jobject clazz, jint maxThreads)
+{
+    ProcessState::self()->setThreadPoolMaxThreadCount(maxThreads);
+}
+
 static void android_os_BinderInternal_handleGc(JNIEnv* env, jobject clazz)
 {
     ALOGV("Gc has executed, clearing binder ops");
@@ -930,6 +936,7 @@
     { "getContextObject", "()Landroid/os/IBinder;", (void*)android_os_BinderInternal_getContextObject },
     { "joinThreadPool", "()V", (void*)android_os_BinderInternal_joinThreadPool },
     { "disableBackgroundScheduling", "(Z)V", (void*)android_os_BinderInternal_disableBackgroundScheduling },
+    { "setMaxThreads", "(I)V", (void*)android_os_BinderInternal_setMaxThreads },
     { "handleGc", "()V", (void*)android_os_BinderInternal_handleGc }
 };
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index a598096..acf9675 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -347,10 +347,6 @@
     <protected-broadcast android:name="android.app.action.SYSTEM_UPDATE_POLICY_CHANGED" />
     <protected-broadcast android:name="android.app.action.DEVICE_OWNER_CHANGED" />
 
-    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABILITY_CHANGED" />
-    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_AVAILABLE" />
-    <protected-broadcast android:name="android.intent.action.MANAGED_PROFILE_UNAVAILABLE" />
-
     <!-- Added in N -->
     <protected-broadcast android:name="android.intent.action.ANR" />
     <protected-broadcast android:name="android.intent.action.CALL" />
@@ -1591,9 +1587,10 @@
     <permission android:name="android.permission.INTERACT_ACROSS_USERS"
         android:protectionLevel="signature|privileged|development" />
 
-    <!-- @hide Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
+    <!-- @SystemApi Fuller form of {@link android.Manifest.permission#INTERACT_ACROSS_USERS}
          that removes restrictions on where broadcasts can be sent and allows other
-         types of interactions. -->
+         types of interactions
+         @hide -->
     <permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL"
         android:protectionLevel="signature|installer" />
 
@@ -2086,11 +2083,12 @@
         android:protectionLevel="signature|privileged|development" />
 
     <!-- @SystemApi Allows an application to update application operation statistics. Not for
-         use by third party apps. @hide -->
+         use by third party apps.
+         @hide -->
     <permission android:name="android.permission.UPDATE_APP_OPS_STATS"
         android:protectionLevel="signature|privileged|installer" />
 
-    <!-- Allows an application to update the user app op restrictions.
+    <!-- @SystemApi Allows an application to update the user app op restrictions.
          Not for use by third party apps.
          @hide -->
     <permission android:name="android.permission.MANAGE_APP_OPS_RESTRICTIONS"
@@ -2236,7 +2234,13 @@
     <permission android:name="android.permission.BIND_PRINT_SPOOLER_SERVICE"
         android:protectionLevel="signature" />
 
-    <!-- Must be required by a TextService (eg SpellCheckerService)
+    <!-- @SystemApi Must be required by the RuntimePermissionPresenterService to ensure
+         that only the system can bind to it.
+         @hide -->
+    <permission android:name="android.permission.BIND_RUNTIME_PERMISSION_PRESENTER_SERVICE"
+        android:protectionLevel="signature" />
+
+    <!-- Must be required by a TextService (e.g. SpellCheckerService)
          to ensure that only the system can bind to it.
          <p>Protection level: signature
     -->
@@ -2283,6 +2287,23 @@
     <permission android:name="android.permission.BIND_TV_INPUT"
         android:protectionLevel="signature|privileged" />
 
+    <!-- @SystemApi
+         Must be required by a {@link com.android.media.tv.remoteprovider.TvRemoteProvider}
+         to ensure that only the system can bind to it.
+         <p>Protection level: signature|privileged
+         <p>Not for use by third-party applications. </p>
+         @hide  -->
+    <permission android:name="android.permission.BIND_TV_REMOTE_SERVICE"
+        android:protectionLevel="signature|privileged" />
+
+    <!-- @SystemApi
+         Must be required for a virtual remote controller for TV.
+         <p>Protection level: signature|privileged
+         <p>Not for use by third-party applications. </p>
+         @hide  -->
+    <permission android:name="android.permission.TV_VIRTUAL_REMOTE_CONTROLLER"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an application to modify parental controls
          <p>Not for use by third-party applications.
          @hide -->
@@ -2400,21 +2421,19 @@
     <permission android:name="android.permission.CHANGE_COMPONENT_ENABLED_STATE"
         android:protectionLevel="signature|privileged" />
 
-    <!-- Allows an application to grant specific permissions.
+    <!-- @SystemApi Allows an application to grant specific permissions.
          @hide -->
     <permission android:name="android.permission.GRANT_RUNTIME_PERMISSIONS"
         android:protectionLevel="signature|installer|verifier" />
 
-    <!-- Allows an app that has this permission and the permissions to install packages
+    <!-- @SystemApi Allows an app that has this permission and the permissions to install packages
          to request certain runtime permissions to be granted at installation.
-         @hide
-         @SystemApi -->
+         @hide -->
     <permission android:name="android.permission.INSTALL_GRANT_RUNTIME_PERMISSIONS"
         android:protectionLevel="signature|installer|verifier" />
 
-    <!-- Allows an application to revoke specific permissions.
-        @hide
-        @SystemApi -->
+    <!-- @SystemApi Allows an application to revoke specific permissions.
+        @hide -->
     <permission android:name="android.permission.REVOKE_RUNTIME_PERMISSIONS"
          android:protectionLevel="signature|installer|verifier" />
 
@@ -2950,7 +2969,7 @@
     <permission android:name="android.permission.QUERY_DO_NOT_ASK_CREDENTIALS_ON_BOOT"
                 android:protectionLevel="signature" />
 
-    <!-- Allows applications to kill UIDs.
+    <!-- @SystemApi Allows applications to kill UIDs.
         <p>Not for use by third-party applications.
          @hide -->
     <permission android:name="android.permission.KILL_UID"
diff --git a/core/res/res/layout/notification_template_header.xml b/core/res/res/layout/notification_template_header.xml
index 992e88e..d16dcc6 100644
--- a/core/res/res/layout/notification_template_header.xml
+++ b/core/res/res/layout/notification_template_header.xml
@@ -69,15 +69,17 @@
         android:text="@string/notification_header_divider_symbol"
         android:singleLine="true"
         android:visibility="gone"/>
-    <ViewStub
+    <DateTimeView
         android:id="@+id/time"
+        android:textAppearance="@style/TextAppearance.Material.Notification.Time"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center"
         android:layout_marginStart="2dp"
         android:layout_marginEnd="2dp"
-        android:layout="@layout/notification_template_part_time"
-        android:visibility="gone"
-        />
+        android:showRelative="true"
+        android:singleLine="true"
+        android:visibility="gone" />
     <ViewStub
         android:id="@+id/chronometer"
         android:layout_width="wrap_content"
diff --git a/core/res/res/layout/notification_template_part_time.xml b/core/res/res/layout/notification_template_part_time.xml
deleted file mode 100644
index 442ff8c..0000000
--- a/core/res/res/layout/notification_template_part_time.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2012 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<DateTimeView android:id="@+id/time" xmlns:android="http://schemas.android.com/apk/res/android"
-    android:textAppearance="@style/TextAppearance.Material.Notification.Time"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:layout_gravity="center"
-    android:layout_marginEnd="4dp"
-    android:layout_weight="0"
-    android:singleLine="true"
-    />
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 5bfa2d4..6af9ef2 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8083,11 +8083,11 @@
         <attr name="settingsActivity" />
         <!-- Attribute whether the TV input service can record programs. This value can be changed
              at runtime by calling
-             {@link android.media.tv.TvInputService#updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo)}. -->
+             {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}. -->
         <attr name="canRecord" format="boolean" />
         <!-- The number of tuners that the TV input service is associated with. This value can be
              changed at runtime by calling
-             {@link android.media.tv.TvInputService#updateTvInputInfo(android.content.Context, android.media.tv.TvInputInfo)}. -->
+             {@link android.media.tv.TvInputManager#updateTvInputInfo(android.media.tv.TvInputInfo)}. -->
         <attr name="tunerCount" format="integer" />
     </declare-styleable>
 
@@ -8134,6 +8134,10 @@
         <attr name="spacing" />
     </declare-styleable>
 
+    <declare-styleable name="DateTimeView">
+        <attr name="showRelative" format="boolean" />
+    </declare-styleable>
+
     <declare-styleable name="ResolverDrawerLayout_LayoutParams">
         <attr name="layout_alwaysShow" format="boolean" />
         <attr name="layout_ignoreOffset" format="boolean" />
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index aada05d..789a417 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2474,4 +2474,8 @@
     -->
     <integer name="config_externalHardKeyboardBehavior">0</integer>
 
+    <!-- Package of the unbundled tv remote service which can connect to tv
+         remote provider -->
+    <string name="config_tvRemoteServicePackage" translatable="false"></string>
+
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 6776d3b..03c6048 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -497,14 +497,14 @@
     <string name="bugreport_option_interactive_title">Interactive report</string>
     <!-- Summary in the bugreport dialog for the interactive workflow. [CHAR LIMIT=NONE] -->
     <string name="bugreport_option_interactive_summary">Use this under most circumstances.
-        It allows you to track progress of the report and enter more details about the problem.
+        It allows you to track progress of the report, enter more details about the problem, and take screenshots.
         It might omit some less-used sections that take a long time to report.</string>
     <!-- Title in the bugreport dialog for the full workflow. Should fit in one line. [CHAR LIMIT=30] -->
     <string name="bugreport_option_full_title">Full report</string>
     <!-- Summary in the bugreport dialog for the full workflow. [CHAR LIMIT=NONE] -->
     <string name="bugreport_option_full_summary">Use this option for minimal system interference when
         your device is unresponsive or too slow, or when you need all report sections.
-        Does not take a screenshot or allow you to enter more details.</string>
+        Does not allow you to enter more details or take additional screenshots.</string>
     <!--  Toast message informing user in how many seconds a bugreport screenshot will be taken -->
     <plurals name="bugreport_countdown">
         <item quantity="one">Taking screenshot for bug report in <xliff:g id="number">%d</xliff:g> second.</item>
@@ -2423,6 +2423,49 @@
         <item quantity="other"><xliff:g id="count">%d</xliff:g> hours</item>
     </plurals>
 
+    <!-- A string denoting the current point in time that should be as short as possible. Abbreviations are preferred to full strings as this might be shown repetitively. It is used in the header of notifications. [CHAR LIMIT=8]-->
+    <string name="now_string_shortest">now</string>
+
+    <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
+    <plurals name="duration_minutes_shortest">
+        <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>m</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
+    <plurals name="duration_hours_shortest">
+        <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>h</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
+    <plurals name="duration_days_shortest">
+        <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>d</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=6] -->
+    <plurals name="duration_years_shortest">
+        <item quantity="other"><xliff:g example="2" id="count">%d</xliff:g>y</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using minutes that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <plurals name="duration_minutes_shortest_future">
+        <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>m</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using hours that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <plurals name="duration_hours_shortest_future">
+        <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>h</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using days that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <plurals name="duration_days_shortest_future">
+        <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>d</item>
+    </plurals>
+
+    <!-- Phrase describing a time duration using years that is as short as possible, preferrably one character. This version should be a future point in time. If the language needs a space in between the integer and the unit, please also integrate it in the string, but preferably it should not have a space in between.[CHAR LIMIT=14] -->
+    <plurals name="duration_years_shortest_future">
+        <item quantity="other">in <xliff:g example="2" id="count">%d</xliff:g>y</item>
+    </plurals>
+
     <!-- Title for error alert when a video cannot be played.  it can be used by any app. -->
     <string name="VideoView_error_title">Video problem</string>
     <!-- Text for error alert when a video container is not valid for progressive download/playback. -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 60060a3..95f65de 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2508,6 +2508,17 @@
 
   <java-symbol type="id" name="notification_content_container" />
 
+  <java-symbol type="plurals" name="duration_minutes_shortest" />
+  <java-symbol type="plurals" name="duration_hours_shortest" />
+  <java-symbol type="plurals" name="duration_days_shortest" />
+  <java-symbol type="plurals" name="duration_years_shortest" />
+  <java-symbol type="plurals" name="duration_minutes_shortest_future" />
+  <java-symbol type="plurals" name="duration_hours_shortest_future" />
+  <java-symbol type="plurals" name="duration_days_shortest_future" />
+  <java-symbol type="plurals" name="duration_years_shortest_future" />
+
+  <java-symbol type="string" name="now_string_shortest" />
+
   <!-- Encryption notification while accounts are locked by credential encryption -->
   <java-symbol type="string" name="user_encrypted_title" />
   <java-symbol type="string" name="user_encrypted_message" />
@@ -2563,4 +2574,7 @@
 
   <java-symbol type="dimen" name="input_extract_action_button_width" />
   <java-symbol type="dimen" name="input_extract_action_button_height" />
+
+  <!-- TV Remote Service package -->
+  <java-symbol type="string" name="config_tvRemoteServicePackage" />
 </resources>
diff --git a/docs/html/training/tv/playback/browse.jd b/docs/html/training/tv/playback/browse.jd
index fee6a74..4621389 100644
--- a/docs/html/training/tv/playback/browse.jd
+++ b/docs/html/training/tv/playback/browse.jd
@@ -166,7 +166,7 @@
   shown in figures 1 and 2. This method replaces the title string with the
   drawable resource, if {@code setTitle()} is also called. The drawable resource should be 52dps
   tall.</li>
-  <li>{@link android.support.v17.leanback.app.BrowseFragment#setTitle(java.lang.String) setTitle()}
+  <li>{@link android.support.v17.leanback.app.BrowseFragment#setTitle(java.lang.CharSequence) setTitle()}
   sets the title string in the upper-right corner of the browse fragment, unless
   {@code setBadgeDrawable()} is called.</li>
   <li>{@link android.support.v17.leanback.app.BrowseFragment#setHeadersState(int) setHeadersState()}
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 15cb684..c3dfb89 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -562,7 +562,7 @@
 
         if ((mHeader->flags&ResStringPool_header::UTF8_FLAG &&
                 ((uint8_t*)mStrings)[mStringPoolSize-1] != 0) ||
-                (!mHeader->flags&ResStringPool_header::UTF8_FLAG &&
+                (!(mHeader->flags&ResStringPool_header::UTF8_FLAG) &&
                 ((uint16_t*)mStrings)[mStringPoolSize-1] != 0)) {
             ALOGW("Bad string block: last string is not 0-terminated\n");
             return (mError=BAD_TYPE);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index 6259466..8857c41 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -247,6 +247,7 @@
     tests/unit/DamageAccumulatorTests.cpp \
     tests/unit/DeviceInfoTests.cpp \
     tests/unit/FatVectorTests.cpp \
+    tests/unit/FontRendererTests.cpp \
     tests/unit/GlopBuilderTests.cpp \
     tests/unit/GpuMemoryTrackerTests.cpp \
     tests/unit/GradientCacheTests.cpp \
diff --git a/libs/hwui/FontRenderer.cpp b/libs/hwui/FontRenderer.cpp
index 1b618c6..276c18d 100644
--- a/libs/hwui/FontRenderer.cpp
+++ b/libs/hwui/FontRenderer.cpp
@@ -689,7 +689,7 @@
 void FontRenderer::blurImage(uint8_t** image, int32_t width, int32_t height, float radius) {
     uint32_t intRadius = Blur::convertRadiusToInt(radius);
 #ifdef ANDROID_ENABLE_RENDERSCRIPT
-    if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF) {
+    if (width * height * intRadius >= RS_MIN_INPUT_CUTOFF && radius <= 25.0f) {
         uint8_t* outImage = (uint8_t*) memalign(RS_CPU_ALLOCATION_ALIGNMENT, width * height);
 
         if (mRs == nullptr) {
diff --git a/libs/hwui/tests/unit/FontRendererTests.cpp b/libs/hwui/tests/unit/FontRendererTests.cpp
new file mode 100644
index 0000000..99080ac
--- /dev/null
+++ b/libs/hwui/tests/unit/FontRendererTests.cpp
@@ -0,0 +1,55 @@
+/*
+ * 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.
+ */
+
+#include <gtest/gtest.h>
+
+#include "GammaFontRenderer.h"
+#include "tests/common/TestUtils.h"
+
+using namespace android::uirenderer;
+
+static bool isZero(uint8_t* data, int size) {
+    for (int i = 0; i < size; i++) {
+        if (data[i]) return false;
+    }
+    return true;
+}
+
+RENDERTHREAD_TEST(FontRenderer, renderDropShadow) {
+    SkPaint paint;
+    paint.setTextSize(10);
+    paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+    GammaFontRenderer gammaFontRenderer;
+    FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
+    fontRenderer.setFont(&paint, SkMatrix::I());
+
+    std::vector<glyph_t> glyphs;
+    std::vector<float> positions;
+    float totalAdvance;
+    Rect bounds;
+    TestUtils::layoutTextUnscaled(paint, "This is a test",
+            &glyphs, &positions, &totalAdvance, &bounds);
+
+    for (int radius : {28, 20, 2}) {
+        auto result = fontRenderer.renderDropShadow(&paint, glyphs.data(), glyphs.size(),
+                radius, positions.data());
+        ASSERT_NE(nullptr, result.image);
+        EXPECT_FALSE(isZero(result.image, result.width * result.height));
+        EXPECT_LE(bounds.getWidth() + radius * 2, (int) result.width);
+        EXPECT_LE(bounds.getHeight() + radius * 2, (int) result.height);
+        delete result.image;
+    }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 00eff91..23ae691 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1502,11 +1502,16 @@
      */
     public boolean isBluetoothA2dpOn() {
         if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP,"")
-            == AudioSystem.DEVICE_STATE_UNAVAILABLE) {
-            return false;
-        } else {
+                == AudioSystem.DEVICE_STATE_AVAILABLE) {
+            return true;
+        } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_HEADPHONES,"")
+                == AudioSystem.DEVICE_STATE_AVAILABLE) {
+            return true;
+        } else if (AudioSystem.getDeviceConnectionState(DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER,"")
+                == AudioSystem.DEVICE_STATE_AVAILABLE) {
             return true;
         }
+        return false;
     }
 
     /**
diff --git a/media/java/android/media/midi/MidiDevice.java b/media/java/android/media/midi/MidiDevice.java
index e4588fe..da44ca6 100644
--- a/media/java/android/media/midi/MidiDevice.java
+++ b/media/java/android/media/midi/MidiDevice.java
@@ -42,6 +42,7 @@
     private final IMidiManager mMidiManager;
     private final IBinder mClientToken;
     private final IBinder mDeviceToken;
+    private boolean mIsDeviceClosed;
 
     private final CloseGuard mGuard = CloseGuard.get();
 
@@ -123,6 +124,9 @@
      *         or null in case of failure.
      */
     public MidiInputPort openInputPort(int portNumber) {
+        if (mIsDeviceClosed) {
+            return null;
+        }
         try {
             IBinder token = new Binder();
             ParcelFileDescriptor pfd = mDeviceServer.openInputPort(token, portNumber);
@@ -146,6 +150,9 @@
      *         or null in case of failure.
      */
     public MidiOutputPort openOutputPort(int portNumber) {
+        if (mIsDeviceClosed) {
+            return null;
+        }
         try {
             IBinder token = new Binder();
             ParcelFileDescriptor pfd = mDeviceServer.openOutputPort(token, portNumber);
@@ -175,12 +182,15 @@
         if (outputPortNumber < 0 || outputPortNumber >= mDeviceInfo.getOutputPortCount()) {
             throw new IllegalArgumentException("outputPortNumber out of range");
         }
+        if (mIsDeviceClosed) {
+            return null;
+        }
 
         ParcelFileDescriptor pfd = inputPort.claimFileDescriptor();
         if (pfd == null) {
             return null;
         }
-         try {
+        try {
             IBinder token = new Binder();
             int calleePid = mDeviceServer.connectPorts(token, pfd, outputPortNumber);
             // If the service is a different Process then it will duplicate the pfd
@@ -202,11 +212,14 @@
     @Override
     public void close() throws IOException {
         synchronized (mGuard) {
-            mGuard.close();
-            try {
-                mMidiManager.closeDevice(mClientToken, mDeviceToken);
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in closeDevice");
+            if (!mIsDeviceClosed) {
+                mGuard.close();
+                mIsDeviceClosed = true;
+                try {
+                    mMidiManager.closeDevice(mClientToken, mDeviceToken);
+                } catch (RemoteException e) {
+                    Log.e(TAG, "RemoteException in closeDevice");
+                }
             }
         }
     }
diff --git a/media/java/android/media/tv/ITvRemoteProvider.aidl b/media/java/android/media/tv/ITvRemoteProvider.aidl
new file mode 100644
index 0000000..3d9619b
--- /dev/null
+++ b/media/java/android/media/tv/ITvRemoteProvider.aidl
@@ -0,0 +1,27 @@
+/*
+ * 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.media.tv;
+
+import android.media.tv.ITvRemoteServiceInput;
+
+/**
+ * {@hide}
+ */
+oneway interface ITvRemoteProvider {
+    void setRemoteServiceInputSink(in ITvRemoteServiceInput tvServiceInput);
+    void onInputBridgeConnected(IBinder token);
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/ITvRemoteServiceInput.aidl b/media/java/android/media/tv/ITvRemoteServiceInput.aidl
new file mode 100644
index 0000000..df39299
--- /dev/null
+++ b/media/java/android/media/tv/ITvRemoteServiceInput.aidl
@@ -0,0 +1,33 @@
+/*
+ * 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.media.tv;
+
+/**
+ * {@hide}
+ */
+oneway interface ITvRemoteServiceInput {
+    // InputBridge related
+    void openInputBridge(IBinder token, String name, int width, int height, int maxPointers);
+    void closeInputBridge(IBinder token);
+    void clearInputBridge(IBinder token);
+    void sendTimestamp(IBinder token, long timestamp);
+    void sendKeyDown(IBinder token, int keyCode);
+    void sendKeyUp(IBinder token, int keyCode);
+    void sendPointerDown(IBinder token, int pointerId, int x, int y);
+    void sendPointerUp(IBinder token, int pointerId);
+    void sendPointerSync(IBinder token);
+}
\ No newline at end of file
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index bfd938e..5c9d2b2 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -191,7 +191,9 @@
     /**
      * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
      * {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
-     * completed due to a problem that does not fit under any other error codes.
+     * completed due to a problem that does not fit under any other error codes, or the error code
+     * for the problem is defined on the higher version than application's
+     * <code>android:targetSdkVersion</code>.
      */
     public static final int RECORDING_ERROR_UNKNOWN = 0;
 
@@ -1181,14 +1183,23 @@
     }
 
     /**
-     * Updates information about an existing TV input.
+     * Updates the <code>TvInputInfo</code> for an existing TV input. A TV input service
+     * implementation may call this method to pass the application and system an up-to-date
+     * <code>TvInputInfo</code> object that describes itself.
      *
-     * <p>This is called internally only by {@link TvInputService}.
+     * <p>The system automatically creates a <code>TvInputInfo</code> object for each TV input,
+     * based on the information collected from the <code>AndroidManifest.xml</code>, thus it is not
+     * necessary to call this method unless such information has changed dynamically.
+     * Use {@link TvInputInfo.Builder} to build a new <code>TvInputInfo</code> object.
+     *
+     * <p>Attempting to change information about a TV input that the calling package does not own
+     * does nothing.
      *
      * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
      * @throws IllegalArgumentException if the argument is {@code null}.
+     * @see TvInputCallback#onTvInputInfoUpdated(TvInputInfo)
      */
-    void updateTvInputInfo(@NonNull TvInputInfo inputInfo) {
+    public void updateTvInputInfo(@NonNull TvInputInfo inputInfo) {
         Preconditions.checkNotNull(inputInfo);
         try {
             mService.updateTvInputInfo(inputInfo, mUserId);
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 21211d7..7ae8da0 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -256,31 +256,6 @@
         return null;
     }
 
-    /**
-     * Updates the <code>TvInputInfo</code> for an existing TV input. A TV input service
-     * implementation may call this method to pass the application and system an up-to-date
-     * <code>TvInputInfo</code> object that describes itself.
-     *
-     * <p>The system automatically creates a <code>TvInputInfo</code> object for each TV input,
-     * based on the information collected from the <code>AndroidManifest.xml</code>, thus it is not
-     * necessary to call this method unless such information has changed dynamically.
-     * Use {@link TvInputInfo.Builder} to build a new <code>TvInputInfo</code> object.
-     *
-     * <p>Attempting to change information about a TV input that the calling package does not own
-     * does nothing.
-     *
-     * @param context The application context.
-     * @param inputInfo The <code>TvInputInfo</code> object that contains new information.
-     * @see TvInputManager.TvInputCallback#onTvInputInfoUpdated(TvInputInfo)
-     */
-    public static final void updateTvInputInfo(Context context, TvInputInfo inputInfo) {
-        TvInputManager manager = (TvInputManager) context.getSystemService(
-                Context.TV_INPUT_SERVICE);
-        if (manager != null) {
-            manager.updateTvInputInfo(inputInfo);
-        }
-    }
-
     private boolean isPassthroughInput(String inputId) {
         if (mTvInputManager == null) {
             mTvInputManager = (TvInputManager) getSystemService(Context.TV_INPUT_SERVICE);
diff --git a/media/java/android/mtp/MtpConstants.java b/media/java/android/mtp/MtpConstants.java
index 0dcc718..5bbf2ec 100644
--- a/media/java/android/mtp/MtpConstants.java
+++ b/media/java/android/mtp/MtpConstants.java
@@ -583,41 +583,41 @@
      */
     public static final int ASSOCIATION_TYPE_GENERIC_FOLDER = 0x0001;
 
-    /** Event code for UNDEFINED event */
+    /** @removed */
     public static final int EVENT_UNDEFINED = 0x4000;
-    /** Event code for CANCEL_TRANSACTION event */
+    /** @removed */
     public static final int EVENT_CANCEL_TRANSACTION = 0x4001;
-    /** Event code for OBJECT_ADDED event */
+    /** @removed */
     public static final int EVENT_OBJECT_ADDED = 0x4002;
-    /** Event code for OBJECT_REMOVED event */
+    /** @removed */
     public static final int EVENT_OBJECT_REMOVED = 0x4003;
-    /** Event code for STORE_ADDED event */
+    /** @removed */
     public static final int EVENT_STORE_ADDED = 0x4004;
-    /** Event code for STORE_REMOVED event */
+    /** @removed */
     public static final int EVENT_STORE_REMOVED = 0x4005;
-    /** Event code for DEVICE_PROP_CHANGED event */
+    /** @removed */
     public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006;
-    /** Event code for OBJECT_INFO_CHANGED event */
+    /** @removed */
     public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007;
-    /** Event code for DEVICE_INFO_CHANGED event */
+    /** @removed */
     public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008;
-    /** Event code for REQUEST_OBJECT_TRANSFER event */
+    /** @removed */
     public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009;
-    /** Event code for STORE_FULL event */
+    /** @removed */
     public static final int EVENT_STORE_FULL = 0x400A;
-    /** Event code for DEVICE_RESET event */
+    /** @removed */
     public static final int EVENT_DEVICE_RESET = 0x400B;
-    /** Event code for STORAGE_INFO_CHANGED event */
+    /** @removed */
     public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C;
-    /** Event code for CAPTURE_COMPLETE event */
+    /** @removed */
     public static final int EVENT_CAPTURE_COMPLETE = 0x400D;
-    /** Event code for UNREPORTED_STATUS event */
+    /** @removed */
     public static final int EVENT_UNREPORTED_STATUS = 0x400E;
-    /** Event code for OBJECT_PROP_CHANGED event */
+    /** @removed */
     public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801;
-    /** Event code for OBJECT_PROP_DESC_CHANGED event */
+    /** @removed */
     public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802;
-    /** Event code for OBJECT_REFERENCES_CHANGED event */
+    /** @removed */
     public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803;
 
     /** Operation code for GetDeviceInfo */
diff --git a/media/java/android/mtp/MtpDevice.java b/media/java/android/mtp/MtpDevice.java
index d0ef37c..4082778 100644
--- a/media/java/android/mtp/MtpDevice.java
+++ b/media/java/android/mtp/MtpDevice.java
@@ -16,6 +16,8 @@
 
 package android.mtp;
 
+import android.annotation.NonNull;
+import android.annotation.Nullable;
 import android.hardware.usb.UsbDevice;
 import android.hardware.usb.UsbDeviceConnection;
 import android.os.CancellationSignal;
@@ -169,8 +171,8 @@
      * @param objectHandle handle of the object to read
      * @param offset Start index of reading range. It must be a non-negative value at most
      *     0xffffffff.
-     * @param size Size of reading range. It must be a non-negative value at most 0xffffffff. If
-     *     0xffffffff is specified, the method obtains the full bytes of object.
+     * @param size Size of reading range. It must be a non-negative value at most Integer.MAX_VALUE
+     *     or 0xffffffff. If 0xffffffff is specified, the method obtains the full bytes of object.
      * @param buffer Array to write data.
      * @return Size of bytes that are actually read.
      */
@@ -190,7 +192,7 @@
      *
      * @param objectHandle handle of the object to read
      * @param offset Start index of reading range. It must be a non-negative value.
-     * @param size Size of reading range. It must be a non-negative value at most 0xffffffff.
+     * @param size Size of reading range. It must be a non-negative value at most Integer.MAX_VALUE.
      * @param buffer Array to write data.
      * @return Size of bytes that are actually read.
      * @see MtpConstants#OPERATION_GET_PARTIAL_OBJECT_64
@@ -317,7 +319,7 @@
      * The returned {@link MtpObjectInfo} has the new object handle field filled in.
      *
      * @param info metadata of the entry
-     * @return object info of the created entry
+     * @return object info of the created entry or null if the operation failed.
      */
     public MtpObjectInfo sendObjectInfo(MtpObjectInfo info) {
         return native_send_object_info(info);
@@ -329,13 +331,11 @@
      *
      * @param signal signal for cancellation
      * @return obtained event
+     * @throws IOException
      */
-    public MtpEvent readEvent(CancellationSignal signal) {
+    public @NonNull MtpEvent readEvent(@Nullable CancellationSignal signal) throws IOException {
         final int handle = native_submit_event_request();
-
-        if (handle < 0) {
-            throw new IllegalStateException("Other thread is reading an event.");
-        }
+        Preconditions.checkState(handle >= 0, "Other thread is reading an event.");
 
         if (signal != null) {
             signal.setOnCancelListener(new CancellationSignal.OnCancelListener() {
@@ -391,8 +391,8 @@
     private native boolean native_import_file(int objectHandle, int fd);
     private native boolean native_send_object(int objectHandle, long size, int fd);
     private native MtpObjectInfo native_send_object_info(MtpObjectInfo info);
-    private native int native_submit_event_request();
-    private native MtpEvent native_reap_event_request(int handle);
+    private native int native_submit_event_request() throws IOException;
+    private native MtpEvent native_reap_event_request(int handle) throws IOException;
     private native void native_discard_event_request(int handle);
     private native long native_get_object_size_long(int handle, int format) throws IOException;
 }
diff --git a/media/java/android/mtp/MtpDeviceInfo.java b/media/java/android/mtp/MtpDeviceInfo.java
index 2e4f451..86bd599 100644
--- a/media/java/android/mtp/MtpDeviceInfo.java
+++ b/media/java/android/mtp/MtpDeviceInfo.java
@@ -16,8 +16,6 @@
 
 package android.mtp;
 
-import android.annotation.Nullable;
-
 /**
  * This class encapsulates information about an MTP device.
  * This corresponds to the DeviceInfo Dataset described in
@@ -112,7 +110,7 @@
      * @see MtpConstants#OPERATION_SET_OBJECT_REFERENCES
      * @see MtpConstants#OPERATION_SKIP
      */
-    public final @Nullable int[] getOperationsSupported() {
+    public final int[] getOperationsSupported() {
         return mOperationsSupported;
     }
 
@@ -120,26 +118,57 @@
      * Returns event code supported by the device.
      *
      * @return supported event code. Can be null if device does not provide the property.
-     * @see MtpConstants#EVENT_UNDEFINED
-     * @see MtpConstants#EVENT_CANCEL_TRANSACTION
-     * @see MtpConstants#EVENT_OBJECT_ADDED
-     * @see MtpConstants#EVENT_OBJECT_REMOVED
-     * @see MtpConstants#EVENT_STORE_ADDED
-     * @see MtpConstants#EVENT_STORE_REMOVED
-     * @see MtpConstants#EVENT_DEVICE_PROP_CHANGED
-     * @see MtpConstants#EVENT_OBJECT_INFO_CHANGED
-     * @see MtpConstants#EVENT_DEVICE_INFO_CHANGED
-     * @see MtpConstants#EVENT_REQUEST_OBJECT_TRANSFER
-     * @see MtpConstants#EVENT_STORE_FULL
-     * @see MtpConstants#EVENT_DEVICE_RESET
-     * @see MtpConstants#EVENT_STORAGE_INFO_CHANGED
-     * @see MtpConstants#EVENT_CAPTURE_COMPLETE
-     * @see MtpConstants#EVENT_UNREPORTED_STATUS
-     * @see MtpConstants#EVENT_OBJECT_PROP_CHANGED
-     * @see MtpConstants#EVENT_OBJECT_PROP_DESC_CHANGED
-     * @see MtpConstants#EVENT_OBJECT_REFERENCES_CHANGED
+     * @see MtpEvent#EVENT_UNDEFINED
+     * @see MtpEvent#EVENT_CANCEL_TRANSACTION
+     * @see MtpEvent#EVENT_OBJECT_ADDED
+     * @see MtpEvent#EVENT_OBJECT_REMOVED
+     * @see MtpEvent#EVENT_STORE_ADDED
+     * @see MtpEvent#EVENT_STORE_REMOVED
+     * @see MtpEvent#EVENT_DEVICE_PROP_CHANGED
+     * @see MtpEvent#EVENT_OBJECT_INFO_CHANGED
+     * @see MtpEvent#EVENT_DEVICE_INFO_CHANGED
+     * @see MtpEvent#EVENT_REQUEST_OBJECT_TRANSFER
+     * @see MtpEvent#EVENT_STORE_FULL
+     * @see MtpEvent#EVENT_DEVICE_RESET
+     * @see MtpEvent#EVENT_STORAGE_INFO_CHANGED
+     * @see MtpEvent#EVENT_CAPTURE_COMPLETE
+     * @see MtpEvent#EVENT_UNREPORTED_STATUS
+     * @see MtpEvent#EVENT_OBJECT_PROP_CHANGED
+     * @see MtpEvent#EVENT_OBJECT_PROP_DESC_CHANGED
+     * @see MtpEvent#EVENT_OBJECT_REFERENCES_CHANGED
      */
-    public final @Nullable int[] getEventsSupported() {
+    public final int[] getEventsSupported() {
         return mEventsSupported;
     }
+
+    /**
+     * Returns if the given operation is supported by the device or not.
+     * @param code Operation code.
+     * @return If the given operation is supported by the device or not.
+     */
+    public boolean isOperationSupported(int code) {
+        return isSupported(mOperationsSupported, code);
+    }
+
+    /**
+     * Returns if the given event is supported by the device or not.
+     * @param code Event code.
+     * @return If the given event is supported by the device or not.
+     */
+    public boolean isEventSupported(int code) {
+        return isSupported(mEventsSupported, code);
+    }
+
+    /**
+     * Returns if the code set contains code.
+     * @hide
+     */
+    private static boolean isSupported(int[] set, int code) {
+        for (final int element : set) {
+            if (element == code) {
+                return true;
+            }
+        }
+        return false;
+    }
 }
diff --git a/media/java/android/mtp/MtpEvent.java b/media/java/android/mtp/MtpEvent.java
index dc89a56..9ca00e1 100644
--- a/media/java/android/mtp/MtpEvent.java
+++ b/media/java/android/mtp/MtpEvent.java
@@ -21,7 +21,44 @@
  * This corresponds to the events described in appendix G of the MTP specification.
  */
 public class MtpEvent {
-    private int mEventCode = MtpConstants.EVENT_UNDEFINED;
+    /** Event code for UNDEFINED event */
+    public static final int EVENT_UNDEFINED = 0x4000;
+    /** Event code for CANCEL_TRANSACTION event */
+    public static final int EVENT_CANCEL_TRANSACTION = 0x4001;
+    /** Event code for OBJECT_ADDED event */
+    public static final int EVENT_OBJECT_ADDED = 0x4002;
+    /** Event code for OBJECT_REMOVED event */
+    public static final int EVENT_OBJECT_REMOVED = 0x4003;
+    /** Event code for STORE_ADDED event */
+    public static final int EVENT_STORE_ADDED = 0x4004;
+    /** Event code for STORE_REMOVED event */
+    public static final int EVENT_STORE_REMOVED = 0x4005;
+    /** Event code for DEVICE_PROP_CHANGED event */
+    public static final int EVENT_DEVICE_PROP_CHANGED = 0x4006;
+    /** Event code for OBJECT_INFO_CHANGED event */
+    public static final int EVENT_OBJECT_INFO_CHANGED = 0x4007;
+    /** Event code for DEVICE_INFO_CHANGED event */
+    public static final int EVENT_DEVICE_INFO_CHANGED = 0x4008;
+    /** Event code for REQUEST_OBJECT_TRANSFER event */
+    public static final int EVENT_REQUEST_OBJECT_TRANSFER = 0x4009;
+    /** Event code for STORE_FULL event */
+    public static final int EVENT_STORE_FULL = 0x400A;
+    /** Event code for DEVICE_RESET event */
+    public static final int EVENT_DEVICE_RESET = 0x400B;
+    /** Event code for STORAGE_INFO_CHANGED event */
+    public static final int EVENT_STORAGE_INFO_CHANGED = 0x400C;
+    /** Event code for CAPTURE_COMPLETE event */
+    public static final int EVENT_CAPTURE_COMPLETE = 0x400D;
+    /** Event code for UNREPORTED_STATUS event */
+    public static final int EVENT_UNREPORTED_STATUS = 0x400E;
+    /** Event code for OBJECT_PROP_CHANGED event */
+    public static final int EVENT_OBJECT_PROP_CHANGED = 0xC801;
+    /** Event code for OBJECT_PROP_DESC_CHANGED event */
+    public static final int EVENT_OBJECT_PROP_DESC_CHANGED = 0xC802;
+    /** Event code for OBJECT_REFERENCES_CHANGED event */
+    public static final int EVENT_OBJECT_REFERENCES_CHANGED = 0xC803;
+
+    private int mEventCode = EVENT_UNDEFINED;
 
     // Parameters for event. The interpretation of event parameters depends upon mEventCode.
     private int mParameter1;
@@ -29,6 +66,11 @@
     private int mParameter3;
 
     /**
+     * MtpEvent is instantiated by JNI.
+     */
+    private MtpEvent() {}
+
+    /**
      * Returns event code of MTP event.
      * See the USB-IF MTP specification for the details of event constants.
      * @return event code
@@ -53,26 +95,26 @@
     /**
      * Obtains objectHandle event parameter.
      *
-     * @see MtpConstants#EVENT_OBJECT_ADDED
-     * @see MtpConstants#EVENT_OBJECT_REMOVED
-     * @see MtpConstants#EVENT_OBJECT_INFO_CHANGED
-     * @see MtpConstants#EVENT_REQUEST_OBJECT_TRANSFER
-     * @see MtpConstants#EVENT_OBJECT_PROP_CHANGED
-     * @see MtpConstants#EVENT_OBJECT_REFERENCES_CHANGED
+     * @see #EVENT_OBJECT_ADDED
+     * @see #EVENT_OBJECT_REMOVED
+     * @see #EVENT_OBJECT_INFO_CHANGED
+     * @see #EVENT_REQUEST_OBJECT_TRANSFER
+     * @see #EVENT_OBJECT_PROP_CHANGED
+     * @see #EVENT_OBJECT_REFERENCES_CHANGED
      */
     public int getObjectHandle() {
         switch (mEventCode) {
-            case MtpConstants.EVENT_OBJECT_ADDED:
+            case EVENT_OBJECT_ADDED:
                 return mParameter1;
-            case MtpConstants.EVENT_OBJECT_REMOVED:
+            case EVENT_OBJECT_REMOVED:
                 return mParameter1;
-            case MtpConstants.EVENT_OBJECT_INFO_CHANGED:
+            case EVENT_OBJECT_INFO_CHANGED:
                 return mParameter1;
-            case MtpConstants.EVENT_REQUEST_OBJECT_TRANSFER:
+            case EVENT_REQUEST_OBJECT_TRANSFER:
                 return mParameter1;
-            case MtpConstants.EVENT_OBJECT_PROP_CHANGED:
+            case EVENT_OBJECT_PROP_CHANGED:
                 return mParameter1;
-            case MtpConstants.EVENT_OBJECT_REFERENCES_CHANGED:
+            case EVENT_OBJECT_REFERENCES_CHANGED:
                 return mParameter1;
             default:
                 throw new IllegalParameterAccess("objectHandle", mEventCode);
@@ -82,20 +124,20 @@
     /**
      * Obtains storageID event parameter.
      *
-     * @see MtpConstants#EVENT_STORE_ADDED
-     * @see MtpConstants#EVENT_STORE_REMOVED
-     * @see MtpConstants#EVENT_STORE_FULL
-     * @see MtpConstants#EVENT_STORAGE_INFO_CHANGED
+     * @see #EVENT_STORE_ADDED
+     * @see #EVENT_STORE_REMOVED
+     * @see #EVENT_STORE_FULL
+     * @see #EVENT_STORAGE_INFO_CHANGED
      */
     public int getStorageId() {
         switch (mEventCode) {
-            case MtpConstants.EVENT_STORE_ADDED:
+            case EVENT_STORE_ADDED:
                 return mParameter1;
-            case MtpConstants.EVENT_STORE_REMOVED:
+            case EVENT_STORE_REMOVED:
                 return mParameter1;
-            case MtpConstants.EVENT_STORE_FULL:
+            case EVENT_STORE_FULL:
                 return mParameter1;
-            case MtpConstants.EVENT_STORAGE_INFO_CHANGED:
+            case EVENT_STORAGE_INFO_CHANGED:
                 return mParameter1;
             default:
                 throw new IllegalParameterAccess("storageID", mEventCode);
@@ -105,11 +147,11 @@
     /**
      * Obtains devicePropCode event parameter.
      *
-     * @see MtpConstants#EVENT_DEVICE_PROP_CHANGED
+     * @see #EVENT_DEVICE_PROP_CHANGED
      */
     public int getDevicePropCode() {
         switch (mEventCode) {
-            case MtpConstants.EVENT_DEVICE_PROP_CHANGED:
+            case EVENT_DEVICE_PROP_CHANGED:
                 return mParameter1;
             default:
                 throw new IllegalParameterAccess("devicePropCode", mEventCode);
@@ -119,11 +161,11 @@
     /**
      * Obtains transactionID event parameter.
      *
-     * @see MtpConstants#EVENT_CAPTURE_COMPLETE
+     * @see #EVENT_CAPTURE_COMPLETE
      */
     public int getTransactionId() {
         switch (mEventCode) {
-            case MtpConstants.EVENT_CAPTURE_COMPLETE:
+            case EVENT_CAPTURE_COMPLETE:
                 return mParameter1;
             default:
                 throw new IllegalParameterAccess("transactionID", mEventCode);
@@ -133,14 +175,14 @@
     /**
      * Obtains objectPropCode event parameter.
      *
-     * @see MtpConstants#EVENT_OBJECT_PROP_CHANGED
-     * @see MtpConstants#EVENT_OBJECT_PROP_DESC_CHANGED
+     * @see #EVENT_OBJECT_PROP_CHANGED
+     * @see #EVENT_OBJECT_PROP_DESC_CHANGED
      */
     public int getObjectPropCode() {
         switch (mEventCode) {
-            case MtpConstants.EVENT_OBJECT_PROP_CHANGED:
+            case EVENT_OBJECT_PROP_CHANGED:
                 return mParameter2;
-            case MtpConstants.EVENT_OBJECT_PROP_DESC_CHANGED:
+            case EVENT_OBJECT_PROP_DESC_CHANGED:
                 return mParameter1;
             default:
                 throw new IllegalParameterAccess("objectPropCode", mEventCode);
@@ -150,11 +192,11 @@
     /**
      * Obtains objectFormatCode event parameter.
      *
-     * @see MtpConstants#EVENT_OBJECT_PROP_DESC_CHANGED
+     * @see #EVENT_OBJECT_PROP_DESC_CHANGED
      */
     public int getObjectFormatCode() {
         switch (mEventCode) {
-            case MtpConstants.EVENT_OBJECT_PROP_DESC_CHANGED:
+            case EVENT_OBJECT_PROP_DESC_CHANGED:
                 return mParameter2;
             default:
                 throw new IllegalParameterAccess("objectFormatCode", mEventCode);
diff --git a/media/jni/android_mtp_MtpDevice.cpp b/media/jni/android_mtp_MtpDevice.cpp
index 6e434b2..1faa0c4 100644
--- a/media/jni/android_mtp_MtpDevice.cpp
+++ b/media/jni/android_mtp_MtpDevice.cpp
@@ -244,7 +244,8 @@
     if (deviceInfo->mSerial)
         env->SetObjectField(info, field_deviceInfo_serialNumber,
             env->NewStringUTF(deviceInfo->mSerial));
-    if (deviceInfo->mOperations) {
+    assert(deviceInfo->mOperations);
+    {
         const size_t size = deviceInfo->mOperations->size();
         ScopedLocalRef<jintArray> operations(env, static_cast<jintArray>(env->NewIntArray(size)));
         {
@@ -259,7 +260,8 @@
             env->SetObjectField(info, field_deviceInfo_operationsSupported, operations.get());
         }
     }
-    if (deviceInfo->mEvents) {
+    assert(deviceInfo->mEvents);
+    {
         const size_t size = deviceInfo->mEvents->size();
         ScopedLocalRef<jintArray> events(env, static_cast<jintArray>(env->NewIntArray(size)));
         {
diff --git a/media/lib/tvremote/Android.mk b/media/lib/tvremote/Android.mk
new file mode 100644
index 0000000..06838c2
--- /dev/null
+++ b/media/lib/tvremote/Android.mk
@@ -0,0 +1,48 @@
+#
+# 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.
+#
+LOCAL_PATH := $(call my-dir)
+
+# the tvremoteprovider library
+# ============================================================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE:= com.android.media.tv.remoteprovider
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := \
+            $(call all-java-files-under, java) \
+            $(call all-aidl-files-under, java)
+
+LOCAL_DEX_PREOPT := false
+
+include $(BUILD_JAVA_LIBRARY)
+
+
+# ====  com.android.media.tvremote.xml lib def  ========================
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := com.android.media.tv.remoteprovider.xml
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_MODULE_CLASS := ETC
+
+# This will install the file in /system/etc/permissions
+#
+LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/permissions
+
+LOCAL_SRC_FILES := $(LOCAL_MODULE)
+
+include $(BUILD_PREBUILT)
\ No newline at end of file
diff --git a/media/lib/tvremote/README.txt b/media/lib/tvremote/README.txt
new file mode 100644
index 0000000..9375f02
--- /dev/null
+++ b/media/lib/tvremote/README.txt
@@ -0,0 +1,26 @@
+This library (com.android.media.tv.remoteprovider.jar) is a shared java library
+containing classes required by unbundled atv remote providers.
+
+--- Rules of this library ---
+o This library is effectively a System API for unbundled emote service provider
+  that may be distributed outside the system image. So it MUST BE API STABLE.
+  You can add but not remove. The rules are the same as for the
+  public platform SDK API.
+o This library can see and instantiate internal platform classes, but it must not
+  expose them in any public method (or by extending them via inheritance). This would
+  break clients of the library because they cannot see the internal platform classes.
+
+This library is distributed in the system image, and loaded as
+a shared library. So you can change the implementation, but not
+the interface. In this way it is like framework.jar.
+
+--- Why does this library exist? ---
+
+Unbundled atv remote providers (such as Emote app) cannot use internal
+platform classes.
+
+This library will eventually be replaced when the inputmanager
+infrastructure is ready with APIs allowing unbundled system apps to
+inject events into uhid.
+That API isn't ready yet so this library is a compromise to
+make new capabilities available to the system.
\ No newline at end of file
diff --git a/media/lib/tvremote/com.android.media.tv.remoteprovider.xml b/media/lib/tvremote/com.android.media.tv.remoteprovider.xml
new file mode 100644
index 0000000..dcf479a
--- /dev/null
+++ b/media/lib/tvremote/com.android.media.tv.remoteprovider.xml
@@ -0,0 +1,20 @@
+<?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.
+-->
+
+<permissions>
+    <library name="com.android.media.tv.remoteprovider"
+        file="/system/framework/com.android.media.tv.remoteprovider.jar" />
+</permissions>
\ No newline at end of file
diff --git a/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java b/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
new file mode 100644
index 0000000..35322ad
--- /dev/null
+++ b/media/lib/tvremote/java/com/android/media/tv/remoteprovider/TvRemoteProvider.java
@@ -0,0 +1,303 @@
+/*
+ * 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.media.tv.remoteprovider;
+
+import android.content.Context;
+import android.media.tv.ITvRemoteProvider;
+import android.media.tv.ITvRemoteServiceInput;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.os.RemoteException;
+import android.util.Log;
+
+/**
+ * Base class for emote providers implemented in unbundled service.
+ * <p/>
+ * This object is not thread safe.  It is only intended to be accessed on the
+ * {@link Context#getMainLooper main looper thread} of an application.
+ * </p><p>
+ * IMPORTANT: This class is effectively a system API for unbundled emote service, and
+ * must remain API stable. See README.txt in the root of this package for more information.
+ * </p>
+ */
+
+
+public abstract class TvRemoteProvider {
+
+    /**
+     * The {@link Intent} that must be declared as handled by the service.
+     * The service must also require the {@link android.Manifest.permission#BIND_TV_REMOTE_SERVICE}
+     * permission so that other applications cannot abuse it.
+     */
+    public static final String SERVICE_INTERFACE =
+            "com.android.media.tv.remoteprovider.TvRemoteProvider";
+
+    private static final String TAG = "TvRemoteProvider";
+    private static final boolean DEBUG_KEYS = false;
+    private static final int MSG_SET_SERVICE_INPUT = 1;
+    private static final int MSG_SEND_INPUTBRIDGE_CONNECTED = 2;
+    private final Context mContext;
+    private final ProviderStub mStub;
+    private final ProviderHandler mHandler;
+    private ITvRemoteServiceInput mRemoteServiceInput;
+
+    /**
+     * Creates a provider for an unbundled emote controller
+     * service allowing it to interface with the tv remote controller
+     * system service.
+     *
+     * @param context The application context for the remote provider.
+     */
+    public TvRemoteProvider(Context context) {
+        mContext = context.getApplicationContext();
+        mStub = new ProviderStub();
+        mHandler = new ProviderHandler(mContext.getMainLooper());
+    }
+
+    /**
+     * Gets the context of the remote service provider.
+     */
+    public final Context getContext() {
+        return mContext;
+    }
+
+
+    /**
+     * Gets the Binder associated with the provider.
+     * <p>
+     * This is intended to be used for the onBind() method of a service that implements
+     * a remote provider service.
+     * </p>
+     *
+     * @return The IBinder instance associated with the provider.
+     */
+    public IBinder getBinder() {
+        return mStub;
+    }
+
+    /**
+     * Information about the InputBridge connected status.
+     *
+     * @param token Identifier for the connection. Null, if failed.
+     */
+    public void onInputBridgeConnected(IBinder token) {
+    }
+
+    /**
+     * Set a sink for sending events to framework service.
+     *
+     * @param tvServiceInput sink defined in framework service
+     */
+    private void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
+        mRemoteServiceInput = tvServiceInput;
+    }
+
+    /**
+     * openRemoteInputBridge : Open an input bridge for a particular device.
+     * Clients should pass in a token that can be used to match this request with a token that
+     * will be returned by {@link TvRemoteProvider#onInputBridgeConnected(IBinder token)}
+     * <p>
+     * The token should be used for subsequent calls.
+     * </p>
+     *
+     * @param name        Device name
+     * @param token       Identifier for this connection
+     * @param width       Width of the device's virtual touchpad
+     * @param height      Height of the device's virtual touchpad
+     * @param maxPointers Maximum supported pointers
+     * @throws RuntimeException
+     */
+    public void openRemoteInputBridge(IBinder token, String name, int width, int height,
+                                      int maxPointers) throws RuntimeException {
+        try {
+            mRemoteServiceInput.openInputBridge(token, name, width, height, maxPointers);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * closeInputBridge : Close input bridge for a device
+     *
+     * @param token identifier for this connection
+     * @throws RuntimeException
+     */
+    public void closeInputBridge(IBinder token) throws RuntimeException {
+        try {
+            mRemoteServiceInput.closeInputBridge(token);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * clearInputBridge : Clear out any existing key or pointer events in queue for this device by
+     *                    dropping them on the floor and sending an UP to all keys and pointer
+     *                    slots.
+     *
+     * @param token identifier for this connection
+     * @throws RuntimeException
+     */
+    public void clearInputBridge(IBinder token) throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "clearInputBridge() token " + token);
+        try {
+            mRemoteServiceInput.clearInputBridge(token);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * sendTimestamp : Send a timestamp for a set of pointer events
+     *
+     * @param token     identifier for the device
+     * @param timestamp Timestamp to be used in
+     *                  {@link android.os.SystemClock#uptimeMillis} time base
+     * @throws RuntimeException
+     */
+    public void sendTimestamp(IBinder token, long timestamp) throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "sendTimestamp() token: " + token +
+                ", timestamp: " + timestamp);
+        try {
+            mRemoteServiceInput.sendTimestamp(token, timestamp);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * sendKeyUp : Send key up event for a device
+     *
+     * @param token   identifier for this connection
+     * @param keyCode Key code to be sent
+     * @throws RuntimeException
+     */
+    public void sendKeyUp(IBinder token, int keyCode) throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "sendKeyUp() token: " + token + ", keyCode: " + keyCode);
+        try {
+            mRemoteServiceInput.sendKeyUp(token, keyCode);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * sendKeyDown : Send key down event for a device
+     *
+     * @param token   identifier for this connection
+     * @param keyCode Key code to be sent
+     * @throws RuntimeException
+     */
+    public void sendKeyDown(IBinder token, int keyCode) throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "sendKeyDown() token: " + token +
+                ", keyCode: " + keyCode);
+        try {
+            mRemoteServiceInput.sendKeyDown(token, keyCode);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * sendPointerUp : Send pointer up event for a device
+     *
+     * @param token     identifier for the device
+     * @param pointerId Pointer id to be used. Value may be from 0
+     *                  to {@link MotionEvent#getPointerCount()} -1
+     * @throws RuntimeException
+     */
+    public void sendPointerUp(IBinder token, int pointerId) throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "sendPointerUp() token: " + token +
+                ", pointerId: " + pointerId);
+        try {
+            mRemoteServiceInput.sendPointerUp(token, pointerId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * sendPointerDown : Send pointer down event for a device
+     *
+     * @param token     identifier for the device
+     * @param pointerId Pointer id to be used. Value may be from 0
+     *                  to {@link MotionEvent#getPointerCount()} -1
+     * @param x         X co-ordinates in display pixels
+     * @param y         Y co-ordinates in display pixels
+     * @throws RuntimeException
+     */
+    public void sendPointerDown(IBinder token, int pointerId, int x, int y)
+            throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "sendPointerDown() token: " + token +
+                ", pointerId: " + pointerId);
+        try {
+            mRemoteServiceInput.sendPointerDown(token, pointerId, x, y);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * sendPointerSync : Send pointer sync event for a device
+     *
+     * @param token identifier for the device
+     * @throws RuntimeException
+     */
+    public void sendPointerSync(IBinder token) throws RuntimeException {
+        if (DEBUG_KEYS) Log.d(TAG, "sendPointerSync() token: " + token);
+        try {
+            mRemoteServiceInput.sendPointerSync(token);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    private final class ProviderStub extends ITvRemoteProvider.Stub {
+        @Override
+        public void setRemoteServiceInputSink(ITvRemoteServiceInput tvServiceInput) {
+            mHandler.obtainMessage(MSG_SET_SERVICE_INPUT, tvServiceInput).sendToTarget();
+        }
+
+        @Override
+        public void onInputBridgeConnected(IBinder token) {
+            mHandler.obtainMessage(MSG_SEND_INPUTBRIDGE_CONNECTED, 0, 0,
+                    (IBinder) token).sendToTarget();
+        }
+    }
+
+    private final class ProviderHandler extends Handler {
+        public ProviderHandler(Looper looper) {
+            super(looper, null, true);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_SET_SERVICE_INPUT: {
+                    setRemoteServiceInputSink((ITvRemoteServiceInput) msg.obj);
+                    break;
+                }
+                case MSG_SEND_INPUTBRIDGE_CONNECTED: {
+                    onInputBridgeConnected((IBinder) msg.obj);
+                    break;
+                }
+            }
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 297fbc7..b67f6a2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -1174,8 +1174,10 @@
             view.setOnDragListener(mOnDragListener);
         }
 
-        // Make all items draggable.
-        view.setOnLongClickListener(onLongClickListener);
+        if (mTuner.allowDragNDrop()) {
+            // Make all items draggable.
+            view.setOnLongClickListener(onLongClickListener);
+        }
     }
 
     private View.OnDragListener mOnDragListener = new View.OnDragListener() {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index ecdbe63..9e2b86a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -70,11 +70,7 @@
     }
 
     public boolean isDocumentEnabled(String docMimeType, int docFlags) {
-        if (isDirectory(docMimeType)) {
-            return true;
-        }
-
-        return MimePredicate.mimeMatches(mState.acceptMimes, docMimeType);
+        return true;
     }
 
     abstract void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch);
@@ -86,6 +82,11 @@
     abstract boolean enableManagedMode();
 
     /**
+     * Whether drag n' drop is allowed in this context
+     */
+    abstract boolean allowDragNDrop();
+
+    /**
      * Provides support for Platform specific specializations of DirectoryFragment.
      */
     private static final class DocumentsTuner extends FragmentTuner {
@@ -195,6 +196,11 @@
         public boolean enableManagedMode() {
             return false;
         }
+
+        @Override
+        public boolean allowDragNDrop() {
+            return false;
+        }
     }
 
     /**
@@ -259,6 +265,11 @@
                     && mState.stack.root.isDownloads()
                     && mState.stack.size() == 1;
         }
+
+        @Override
+        public boolean allowDragNDrop() {
+            return true;
+        }
     }
 
     private static boolean isDirectory(String mimeType) {
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
index 9b1ab0e..ae4519e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/PrintSpoolerService.java
@@ -497,6 +497,20 @@
         }
     }
 
+    /**
+     * Notify all interested parties that a print job has been updated.
+     *
+     * @param printJob The updated print job.
+     */
+    private void notifyPrintJobUpdated(PrintJobInfo printJob) {
+        Message message = mHandlerCaller.obtainMessageO(
+                HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
+                printJob);
+        mHandlerCaller.executeOrSendMessage(message);
+
+        mNotificationController.onUpdateNotifications(mPrintJobs);
+    }
+
     public boolean setPrintJobState(PrintJobId printJobId, int state, String error) {
         boolean success = false;
 
@@ -549,12 +563,7 @@
                     notifyOnAllPrintJobsHandled();
                 }
 
-                Message message = mHandlerCaller.obtainMessageO(
-                        HandlerCallerCallback.MSG_ON_PRINT_JOB_STATE_CHANGED,
-                        printJob);
-                mHandlerCaller.executeOrSendMessage(message);
-
-                mNotificationController.onUpdateNotifications(mPrintJobs);
+                notifyPrintJobUpdated(printJob);
             }
         }
 
@@ -584,9 +593,12 @@
      */
     public void setStatus(@NonNull PrintJobId printJobId, @Nullable CharSequence status) {
         synchronized (mLock) {
-            getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setStatus(status);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
 
-            mNotificationController.onUpdateNotifications(mPrintJobs);
+            if (printJob != null) {
+                printJob.setStatus(status);
+                notifyPrintJobUpdated(printJob);
+            }
         }
     }
 
@@ -600,9 +612,12 @@
     public void setStatus(@NonNull PrintJobId printJobId, @StringRes int status,
             @Nullable CharSequence appPackageName) {
         synchronized (mLock) {
-            getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY).setStatus(status, appPackageName);
+            PrintJobInfo printJob = getPrintJobInfo(printJobId, PrintManager.APP_ID_ANY);
 
-            mNotificationController.onUpdateNotifications(mPrintJobs);
+            if (printJob != null) {
+                printJob.setStatus(status, appPackageName);
+                notifyPrintJobUpdated(printJob);
+            }
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index ca0b86a..d98f1a4 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -20,6 +20,10 @@
 import java.text.NumberFormat;
 
 public class Utils {
+    private static Signature[] sSystemSignature;
+    private static String sPermissionControllerPackageName;
+    private static String sServicesSystemSharedLibPackageName;
+    private static String sSharedSystemSharedLibPackageName;
 
     /**
      * Return string resource that best describes combination of tethering
@@ -161,15 +165,19 @@
         if (sPermissionControllerPackageName == null) {
             sPermissionControllerPackageName = pm.getPermissionControllerPackageName();
         }
+        if (sServicesSystemSharedLibPackageName == null) {
+            sServicesSystemSharedLibPackageName = pm.getServicesSystemSharedLibraryPackageName();
+        }
+        if (sSharedSystemSharedLibPackageName == null) {
+            sSharedSystemSharedLibPackageName = pm.getSharedSystemSharedLibraryPackageName();
+        }
         return (sSystemSignature[0] != null
                         && sSystemSignature[0].equals(getFirstSignature(pkg)))
-                || (sPermissionControllerPackageName != null
-                        && sPermissionControllerPackageName.equals(pkg.packageName));
+                || pkg.packageName.equals(sPermissionControllerPackageName)
+                || pkg.packageName.equals(sServicesSystemSharedLibPackageName)
+                || pkg.packageName.equals(sSharedSystemSharedLibPackageName);
     }
 
-    private static Signature[] sSystemSignature;
-    private static String sPermissionControllerPackageName;
-
     private static Signature getFirstSignature(PackageInfo pkg) {
         if (pkg != null && pkg.signatures != null && pkg.signatures.length > 0) {
             return pkg.signatures[0];
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 8c2af45..9aaddaa 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -1213,44 +1213,55 @@
         }
     }
 
+    /**
+     * Compare by label, then package name, then uid.
+     */
     public static final Comparator<AppEntry> ALPHA_COMPARATOR = new Comparator<AppEntry>() {
         private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
-            return sCollator.compare(object1.label, object2.label);
+            int compareResult = sCollator.compare(object1.label, object2.label);
+            if (compareResult != 0) {
+                return compareResult;
+            }
+            if (object1.info != null && object2.info != null) {
+                compareResult =
+                    sCollator.compare(object1.info.packageName, object2.info.packageName);
+                if (compareResult != 0) {
+                    return compareResult;
+                }
+            }
+            return object1.info.uid - object2.info.uid;
         }
     };
 
     public static final Comparator<AppEntry> SIZE_COMPARATOR
             = new Comparator<AppEntry>() {
-        private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             if (object1.size < object2.size) return 1;
             if (object1.size > object2.size) return -1;
-            return sCollator.compare(object1.label, object2.label);
+            return ALPHA_COMPARATOR.compare(object1, object2);
         }
     };
 
     public static final Comparator<AppEntry> INTERNAL_SIZE_COMPARATOR
             = new Comparator<AppEntry>() {
-        private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             if (object1.internalSize < object2.internalSize) return 1;
             if (object1.internalSize > object2.internalSize) return -1;
-            return sCollator.compare(object1.label, object2.label);
+            return ALPHA_COMPARATOR.compare(object1, object2);
         }
     };
 
     public static final Comparator<AppEntry> EXTERNAL_SIZE_COMPARATOR
             = new Comparator<AppEntry>() {
-        private final Collator sCollator = Collator.getInstance();
         @Override
         public int compare(AppEntry object1, AppEntry object2) {
             if (object1.externalSize < object2.externalSize) return 1;
             if (object1.externalSize > object2.externalSize) return -1;
-            return sCollator.compare(object1.label, object2.label);
+            return ALPHA_COMPARATOR.compare(object1, object2);
         }
     };
 
@@ -1272,21 +1283,18 @@
         }
     };
 
-    public static final AppFilter FILTER_PERSONAL_WITHOUT_DISABLED_UNTIL_USED = new AppFilter() {
-        private int mCurrentUser;
-
+    public static final AppFilter FILTER_WITHOUT_DISABLED_UNTIL_USED = new AppFilter() {
         public void init() {
-            mCurrentUser = ActivityManager.getCurrentUser();
+            // do nothings
         }
 
         @Override
         public boolean filterApp(AppEntry entry) {
-            return UserHandle.getUserId(entry.info.uid) == mCurrentUser &&
-                    entry.info.enabledSetting != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
+            return entry.info.enabledSetting
+                    != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;
         }
     };
 
-
     public static final AppFilter FILTER_WORK = new AppFilter() {
         private int mCurrentUser;
 
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index ec3a7fc..7023a1a 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -198,6 +198,11 @@
     private File mScreenshotsDir;
 
     /**
+     * id of the notification used to set service on foreground.
+     */
+    private int mForegroundId = -1;
+
+    /**
      * Flag indicating whether a screenshot is being taken.
      * <p>
      * This is the only state that is shared between the 2 handlers and hence must have synchronized
@@ -257,6 +262,7 @@
             writer.printf("No monitored processes");
             return;
         }
+        writer.printf("Foreground id: %d\n\n", mForegroundId);
         writer.printf("Monitored dumpstate processes\n");
         writer.printf("-----------------------------\n");
         for (int i = 0; i < size; i++) {
@@ -479,10 +485,21 @@
             return;
         }
         if (DEBUG) {
-            Log.d(TAG, "Sending 'Progress' notification for id " + info.id + "(pid " + info.pid
+            Log.d(TAG, "Sending 'Progress' notification for id " + info.id + " (pid " + info.pid
                     + "): " + percentageText);
         }
-        NotificationManager.from(mContext).notify(TAG, info.id, notification);
+        sendForegroundabledNotification(info.id, notification);
+    }
+
+    private void sendForegroundabledNotification(int id, Notification notification) {
+        if (mForegroundId >= 0) {
+            if (DEBUG) Log.d(TAG, "Already running as foreground service");
+            NotificationManager.from(mContext).notify(id, notification);
+        } else {
+            mForegroundId = id;
+            Log.d(TAG, "Start running as foreground service on id " + mForegroundId);
+            startForeground(mForegroundId, notification);
+        }
     }
 
     /**
@@ -506,8 +523,10 @@
             Log.d(TAG, "Removing ID " + id);
             mProcesses.remove(id);
         }
-        Log.v(TAG, "stopProgress(" + id + "): cancel notification");
-        NotificationManager.from(mContext).cancel(TAG, id);
+        // Must stop foreground service first, otherwise notif.cancel() will fail below.
+        stopForegroundWhenDone(id);
+        Log.d(TAG, "stopProgress(" + id + "): cancel notification");
+        NotificationManager.from(mContext).cancel(id);
         stopSelfWhenDone();
     }
 
@@ -625,7 +644,7 @@
             Log.w(TAG, "launchBugreportInfoDialog(): canceling notification because id " + id
                     + " was not found");
             // TODO: add test case to make sure notification is canceled.
-            NotificationManager.from(mContext).cancel(TAG, id);
+            NotificationManager.from(mContext).cancel(id);
             return;
         }
 
@@ -648,7 +667,7 @@
             Log.w(TAG, "takeScreenshot(): canceling notification because id " + id
                     + " was not found");
             // TODO: add test case to make sure notification is canceled.
-            NotificationManager.from(mContext).cancel(TAG, id);
+            NotificationManager.from(mContext).cancel(id);
             return;
         }
         setTakingScreenshot(true);
@@ -731,7 +750,7 @@
             if (info.finished) {
                 Log.d(TAG, "Screenshot finished after bugreport; updating share notification");
                 info.renameScreenshots(mScreenshotsDir);
-                sendBugreportNotification(mContext, info, mTakingScreenshot);
+                sendBugreportNotification(info, mTakingScreenshot);
             }
             msg = mContext.getString(R.string.bugreport_screenshot_taken);
         } else {
@@ -753,6 +772,33 @@
     }
 
     /**
+     * Stop running on foreground once there is no more active bugreports being watched.
+     */
+    private void stopForegroundWhenDone(int id) {
+        if (id != mForegroundId) {
+            Log.d(TAG, "stopForegroundWhenDone(" + id + "): ignoring since foreground id is "
+                    + mForegroundId);
+            return;
+        }
+
+        Log.d(TAG, "detaching foreground from id " + mForegroundId);
+        stopForeground(Service.STOP_FOREGROUND_DETACH);
+        mForegroundId = -1;
+
+        // Might need to restart foreground using a new notification id.
+        final int total = mProcesses.size();
+        if (total > 0) {
+            for (int i = 0; i < total; i++) {
+                final BugreportInfo info = mProcesses.valueAt(i);
+                if (!info.finished) {
+                    updateProgress(info);
+                    break;
+                }
+            }
+        }
+    }
+
+    /**
      * Finishes the service when it's not monitoring any more processes.
      */
     private void stopSelfWhenDone() {
@@ -797,6 +843,9 @@
         }
         info.finished = true;
 
+        // Stop running on foreground, otherwise share notification cannot be dismissed.
+        stopForegroundWhenDone(id);
+
         final Configuration conf = mContext.getResources().getConfiguration();
         if ((conf.uiMode & Configuration.UI_MODE_TYPE_MASK) != Configuration.UI_MODE_TYPE_WATCH) {
             triggerLocalNotification(mContext, info);
@@ -820,10 +869,10 @@
         boolean isPlainText = info.bugreportFile.getName().toLowerCase().endsWith(".txt");
         if (!isPlainText) {
             // Already zipped, send it right away.
-            sendBugreportNotification(context, info, mTakingScreenshot);
+            sendBugreportNotification(info, mTakingScreenshot);
         } else {
             // Asynchronously zip the file first, then send it.
-            sendZippedBugreportNotification(context, info, mTakingScreenshot);
+            sendZippedBugreportNotification(info, mTakingScreenshot);
         }
     }
 
@@ -905,7 +954,7 @@
             Log.v(TAG, "shareBugReport(): id " + id + " info = " + info);
         }
 
-        addDetailsToZipFile(mContext, info);
+        addDetailsToZipFile(info);
 
         final Intent sendIntent = buildSendIntent(mContext, info);
         if (sendIntent == null) {
@@ -934,36 +983,35 @@
     /**
      * Sends a notification indicating the bugreport has finished so use can share it.
      */
-    private static void sendBugreportNotification(Context context, BugreportInfo info,
-            boolean takingScreenshot) {
+    private void sendBugreportNotification(BugreportInfo info, boolean takingScreenshot) {
 
         // Since adding the details can take a while, do it before notifying user.
-        addDetailsToZipFile(context, info);
+        addDetailsToZipFile(info);
 
         final Intent shareIntent = new Intent(INTENT_BUGREPORT_SHARE);
-        shareIntent.setClass(context, BugreportProgressService.class);
+        shareIntent.setClass(mContext, BugreportProgressService.class);
         shareIntent.setAction(INTENT_BUGREPORT_SHARE);
         shareIntent.putExtra(EXTRA_ID, info.id);
         shareIntent.putExtra(EXTRA_INFO, info);
 
-        final String title = context.getString(R.string.bugreport_finished_title, info.id);
+        final String title = mContext.getString(R.string.bugreport_finished_title, info.id);
         final String content = takingScreenshot ?
-                context.getString(R.string.bugreport_finished_pending_screenshot_text)
-                : context.getString(R.string.bugreport_finished_text);
-        final Notification.Builder builder = newBaseNotification(context)
+                mContext.getString(R.string.bugreport_finished_pending_screenshot_text)
+                : mContext.getString(R.string.bugreport_finished_text);
+        final Notification.Builder builder = newBaseNotification(mContext)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(content)
-                .setContentIntent(PendingIntent.getService(context, info.id, shareIntent,
+                .setContentIntent(PendingIntent.getService(mContext, info.id, shareIntent,
                         PendingIntent.FLAG_UPDATE_CURRENT))
-                .setDeleteIntent(newCancelIntent(context, info));
+                .setDeleteIntent(newCancelIntent(mContext, info));
 
         if (!TextUtils.isEmpty(info.name)) {
             builder.setSubText(info.name);
         }
 
         Log.v(TAG, "Sending 'Share' notification for ID " + info.id + ": " + title);
-        NotificationManager.from(context).notify(TAG, info.id, builder.build());
+        NotificationManager.from(mContext).notify(info.id, builder.build());
     }
 
     /**
@@ -971,14 +1019,14 @@
      * finishes - at this point there is nothing to be done other than waiting, hence it has no
      * pending action.
      */
-    private static void sendBugreportBeingUpdatedNotification(Context context, int id) {
+    private void sendBugreportBeingUpdatedNotification(Context context, int id) {
         final String title = context.getString(R.string.bugreport_updating_title);
         final Notification.Builder builder = newBaseNotification(context)
                 .setContentTitle(title)
                 .setTicker(title)
                 .setContentText(context.getString(R.string.bugreport_updating_wait));
         Log.v(TAG, "Sending 'Updating zip' notification for ID " + id + ": " + title);
-        NotificationManager.from(context).notify(TAG, id, builder.build());
+        sendForegroundabledNotification(id, builder.build());
     }
 
     private static Notification.Builder newBaseNotification(Context context) {
@@ -999,13 +1047,13 @@
     /**
      * Sends a zipped bugreport notification.
      */
-    private static void sendZippedBugreportNotification(final Context context,
-            final BugreportInfo info, final boolean takingScreenshot) {
+    private void sendZippedBugreportNotification( final BugreportInfo info,
+            final boolean takingScreenshot) {
         new AsyncTask<Void, Void, Void>() {
             @Override
             protected Void doInBackground(Void... params) {
                 zipBugreport(info);
-                sendBugreportNotification(context, info, takingScreenshot);
+                sendBugreportNotification(info, takingScreenshot);
                 return null;
             }
         }.execute();
@@ -1043,7 +1091,7 @@
      * If user provided a title, it will be saved into a {@code title.txt} entry; similarly, the
      * description will be saved on {@code description.txt}.
      */
-    private static void addDetailsToZipFile(Context context, BugreportInfo info) {
+    private void addDetailsToZipFile(BugreportInfo info) {
         if (info.bugreportFile == null) {
             // One possible reason is a bug in the Parcelization code.
             Log.wtf(TAG, "addDetailsToZipFile(): no bugreportFile on " + info);
@@ -1061,7 +1109,8 @@
 
         // It's not possible to add a new entry into an existing file, so we need to create a new
         // zip, copy all entries, then rename it.
-        sendBugreportBeingUpdatedNotification(context, info.id); // ...and that takes time
+        sendBugreportBeingUpdatedNotification(mContext, info.id); // ...and that takes time
+
         final File dir = info.bugreportFile.getParentFile();
         final File tmpZip = new File(dir, "tmp-" + info.bugreportFile.getName());
         Log.d(TAG, "Writing temporary zip file (" + tmpZip + ") with title and/or description");
@@ -1090,6 +1139,7 @@
             // Make sure it only tries to add details once, even it fails the first time.
             info.addedDetailsToZip = true;
             info.addingDetailsToZip = false;
+            stopForegroundWhenDone(info.id);
         }
 
         if (!tmpZip.renameTo(info.bugreportFile)) {
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index f76fb26..07c1546 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -241,14 +241,6 @@
     }
 
     public void testProgress_takeExtraScreenshot() throws Exception {
-        takeExtraScreenshotTest(false);
-    }
-
-    public void testProgress_takeExtraScreenshotServiceDiesAfterScreenshotTaken() throws Exception {
-        takeExtraScreenshotTest(true);
-    }
-
-    private void takeExtraScreenshotTest(boolean serviceDies) throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
 
@@ -259,11 +251,6 @@
 
         sendBugreportFinished(ID, mPlainTextPath, mScreenshotPath);
 
-        if (serviceDies) {
-            waitShareNotification(ID);
-            killService();
-        }
-
         Bundle extras = acceptBugreportAndGetSharedIntent(ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, SCREENSHOT_CONTENT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
@@ -272,14 +259,6 @@
     }
 
     public void testScreenshotFinishesAfterBugreport() throws Exception {
-        screenshotFinishesAfterBugreportTest(false);
-    }
-
-    public void testScreenshotFinishesAfterBugreportAndServiceDiesBeforeSharing() throws Exception {
-        screenshotFinishesAfterBugreportTest(true);
-    }
-
-    private void screenshotFinishesAfterBugreportTest(boolean serviceDies) throws Exception {
         resetProperties();
 
         sendBugreportStarted(1000);
@@ -291,10 +270,6 @@
         // There's no indication in the UI about the screenshot finish, so just sleep like a baby...
         Thread.sleep(SAFE_SCREENSHOT_DELAY * DateUtils.SECOND_IN_MILLIS);
 
-        if (serviceDies) {
-            killService();
-        }
-
         Bundle extras = acceptBugreportAndGetSharedIntent(ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT, ID, PID, ZIP_FILE,
                 NAME, NO_TITLE, NO_DESCRIPTION, 1, RENAMED_SCREENSHOTS);
@@ -562,7 +537,7 @@
 
     public void testShareBugreportAfterServiceDies() throws Exception {
         sendBugreportFinished(NO_ID, mPlainTextPath, NO_SCREENSHOT);
-        killService();
+        waitForService(false);
         Bundle extras = acceptBugreportAndGetSharedIntent(NO_ID);
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
     }
@@ -841,15 +816,6 @@
         assertFalse("Service '" + service + "' is still running", isServiceRunning(service));
     }
 
-    private void killService() {
-        waitForService(true);
-        Log.v(TAG, "Stopping service");
-        boolean stopped = mContext.stopService(new Intent(mContext, BugreportProgressService.class));
-        Log.d(TAG, "stopService returned " + stopped);
-        waitForService(false);
-        assertServiceNotRunning();  // Sanity check.
-    }
-
     private boolean isServiceRunning(String name) {
         ActivityManager manager = (ActivityManager) mContext
                 .getSystemService(Context.ACTIVITY_SERVICE);
@@ -878,12 +844,6 @@
                 Thread.currentThread().interrupt();
             }
         }
-        if (!expectRunning) {
-            // Typically happens when service is waiting for a screenshot to finish.
-            Log.w(TAG, "Service didn't stop; try to kill it again");
-            killService();
-            return;
-        }
 
         fail("Service status didn't change to " + expectRunning);
     }
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index c248adf..70c8957 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -508,6 +508,7 @@
         <receiver
             android:name=".statusbar.KeyboardShortcutsReceiver">
             <intent-filter>
+                <action android:name="android.intent.action.DISMISS_KEYBOARD_SHORTCUTS" />
                 <action android:name="android.intent.action.SHOW_KEYBOARD_SHORTCUTS" />
             </intent-filter>
         </receiver>
diff --git a/packages/SystemUI/res/layout/qs_panel.xml b/packages/SystemUI/res/layout/qs_panel.xml
index ef15195..751f181 100644
--- a/packages/SystemUI/res/layout/qs_panel.xml
+++ b/packages/SystemUI/res/layout/qs_panel.xml
@@ -20,7 +20,8 @@
         android:layout_height="wrap_content"
         android:background="@drawable/qs_background_primary"
         android:clipToPadding="false"
-        android:clipChildren="false">
+        android:clipChildren="false"
+        android:elevation="4dp">
 
     <com.android.systemui.qs.QSPanel
             android:id="@+id/quick_settings_panel"
diff --git a/packages/SystemUI/res/layout/recents_incompatible_app_overlay.xml b/packages/SystemUI/res/layout/recents_incompatible_app_overlay.xml
index 2b49dd3..d2daa89 100644
--- a/packages/SystemUI/res/layout/recents_incompatible_app_overlay.xml
+++ b/packages/SystemUI/res/layout/recents_incompatible_app_overlay.xml
@@ -26,5 +26,6 @@
         android:layout_gravity="center"
         android:drawableTop="@drawable/recents_info_light"
         android:drawablePadding="8dp"
-        android:text="@string/recents_incompatible_app_message" />
+        android:text="@string/recents_incompatible_app_message"
+        android:textColor="@android:color/white" />
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index 7460201..2db97a6 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -22,8 +22,7 @@
         android:theme="@style/systemui_theme_remote_input"
         android:id="@+id/remote_input"
         android:layout_height="match_parent"
-        android:layout_width="match_parent"
-        android:paddingEnd="12dp">
+        android:layout_width="match_parent">
 
     <view class="com.android.systemui.statusbar.policy.RemoteInputView$RemoteEditText"
             android:id="@+id/remote_input_text"
@@ -48,19 +47,17 @@
 
     <FrameLayout
             android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical"
-            android:paddingTop="2dp"
-            android:paddingBottom="4dp">
+            android:layout_height="match_parent"
+            android:layout_gravity="center_vertical">
 
         <ImageButton
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_gravity="center"
                 android:paddingStart="12dp"
-                android:paddingEnd="12dp"
-                android:paddingTop="12dp"
-                android:paddingBottom="12dp"
+                android:paddingEnd="24dp"
+                android:paddingTop="16dp"
+                android:paddingBottom="16dp"
                 android:id="@+id/remote_input_send"
                 android:src="@drawable/ic_send"
                 android:contentDescription="@*android:string/ime_action_send"
@@ -72,6 +69,7 @@
                 android:id="@+id/remote_input_progress"
                 android:layout_width="24dp"
                 android:layout_height="24dp"
+                android:layout_marginEnd="6dp"
                 android:layout_gravity="center"
                 android:visibility="invisible"
                 android:indeterminate="true"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index ccefb5f..658571e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -39,8 +39,8 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <com.android.systemui.DensityContainer
-            android:id="@+id/qs_density_container"
+        <com.android.systemui.AutoReinflateContainer
+            android:id="@+id/qs_auto_reinflate_container"
             android:layout="@layout/qs_panel"
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
index 0beeda1..f18a5da 100644
--- a/packages/SystemUI/res/layout/tv_pip_control_button.xml
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -38,5 +38,6 @@
         android:alpha="0"
         android:fontFamily="sans-serif"
         android:textSize="12sp"
-        android:textColor="#EEEEEE" />
+        android:textColor="#EEEEEE"
+        android:importantForAccessibility="no" />
 </merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
index 1e464d8..4a67000 100644
--- a/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_recents_overlay.xml
@@ -23,7 +23,7 @@
     <com.android.systemui.tv.pip.PipRecentsControlsView
         android:id="@+id/pip_controls"
         android:layout_width="wrap_content"
-        android:layout_height="match_parent" />
+        android:layout_height="wrap_content" />
 
     <View
         android:id="@+id/recents"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 1543360..4306fcc 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -98,7 +98,7 @@
         <attr name="metricsAction" format="integer" />
     </declare-styleable>
 
-    <declare-styleable name="DensityContainer">
+    <declare-styleable name="AutoReinflateContainer">
         <attr name="android:layout" />
     </declare-styleable>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ef84c76..e98309e 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -144,12 +144,6 @@
     <!-- The min animation duration for animating the nav bar scrim in. -->
     <integer name="recents_nav_bar_scrim_enter_duration">400</integer>
 
-    <!-- The animation duration for animating the removal of a task view. -->
-    <integer name="recents_animate_task_view_remove_duration">175</integer>
-
-    <!-- The base animation duration for animating the removal of all task views. -->
-    <integer name="recents_animate_task_views_remove_all_duration">300</integer>
-
     <!-- The animation duration for scrolling the stack to a particular item. -->
     <integer name="recents_animate_task_stack_scroll_duration">200</integer>
 
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index ea55ac2..f6c3dd4 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -286,6 +286,9 @@
     <!-- Content description of the bluetooth label showing what we are connected to. [CHAR LIMIT=NONE] -->
     <string name="accessibility_bluetooth_name">Connected to <xliff:g id="bluetooth" example="Car Audio">%s</xliff:g>.</string>
 
+    <!-- Content description of the cast label showing what we are connected to. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_cast_name">Connected to <xliff:g id="cast" example="TV">%s</xliff:g>.</string>
+
 
     <!-- Content description of the WiMAX signal when no signal for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_wimax">No WiMAX.</string>
@@ -363,6 +366,12 @@
     <!-- Content description of the data connection with no SIM for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_no_sim">No SIM.</string>
 
+    <!-- Content description of the cell data. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_cell_data">Cellular Data</string>
+
+    <!-- Content description of the cell data being enabled. [CHAR LIMIT=NONE] -->
+    <string name="accessibility_cell_data_on">Cellular Data On</string>
+
     <!-- Content description of the cell data being disabled. [CHAR LIMIT=NONE] -->
     <string name="accessibility_cell_data_off">Cellular Data Off</string>
 
@@ -378,9 +387,15 @@
     <!-- Content description of the carrier network changing icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_carrier_network_change_mode">Carrier network changing.</string>
 
+    <!-- Content description of button to open battery details icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_details">Open battery details</string>
+
     <!-- Content description of the battery level icon for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_battery_level">Battery <xliff:g id="number">%d</xliff:g> percent.</string>
 
+    <!-- Content description of the battery level icon for accessibility while the device is charging (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_battery_level_charging">Battery charging, <xliff:g id="battery_percentage">%d</xliff:g> percent.</string>
+
     <!-- Content description of the button for showing a settings panel in the notification panel for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_settings_button">System settings.</string>
 
@@ -465,12 +480,16 @@
     <string name="accessibility_quick_settings_dnd_none_on">Do not disturb on, total silence.</string>
     <!-- Content description of the do not disturb tile in quick settings when on in alarms only (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_alarms_on">Do not disturb on, alarms only.</string>
+     <!-- Content description of the do not disturb tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_dnd">Do not disturb.</string>
      <!-- Content description of the do not disturb tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_off">Do not disturb off.</string>
     <!-- Announcement made when do not disturb changes to off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_changed_off">Do not disturb turned off.</string>
     <!-- Announcement made when do not disturb changes to on (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_dnd_changed_on">Do not disturb turned on.</string>
+    <!-- Content description of the bluetooth tile in quick settings (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_bluetooth">Bluetooth.</string>
     <!-- Content description of the bluetooth tile in quick settings when off (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_bluetooth_off">Bluetooth off.</string>
     <!-- Content description of the bluetooth tile in quick settings when on (not shown on the screen). [CHAR LIMIT=NONE] -->
@@ -630,6 +649,10 @@
     <string name="quick_settings_brightness_label">Brightness</string>
     <!-- QuickSettings: Rotation Unlocked [CHAR LIMIT=NONE] -->
     <string name="quick_settings_rotation_unlocked_label">Auto-rotate</string>
+    <!-- Accessibility label for Auto-ratate QuickSettings tile [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_rotation">Auto-rotate screen</string>
+    <!-- Accessibility label for value of Auto-ratate QuickSettings tile [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_rotation_value">Set to <xliff:g name="rotation" example="Portrait">%s</xliff:g></string>
     <!-- QuickSettings: Rotation Locked [CHAR LIMIT=NONE] -->
     <string name="quick_settings_rotation_locked_label">Rotation locked</string>
     <!-- QuickSettings: Locked to Portrait [CHAR LIMIT=NONE] -->
@@ -666,6 +689,8 @@
     <string name="quick_settings_wifi_no_network">No Network</string>
     <!-- QuickSettings: Wifi (Off) [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_off_label">Wi-Fi Off</string>
+    <!-- QuickSettings: Wifi (On) [CHAR LIMIT=NONE] -->
+    <string name="quick_settings_wifi_on_label">Wi-Fi On</string>
     <!-- QuickSettings: Wifi detail panel, text when there are no items [CHAR LIMIT=NONE] -->
     <string name="quick_settings_wifi_detail_empty_text">No Wi-Fi networks available</string>
     <!-- QuickSettings: Cast title [CHAR LIMIT=NONE] -->
@@ -1086,6 +1111,9 @@
     <string name="volume_stream_content_description_vibrate">%1$s. Tap to set to vibrate. Accessibility services may be muted.</string>
     <string name="volume_stream_content_description_mute">%1$s. Tap to mute. Accessibility services may be muted.</string>
 
+    <string name="volume_dialog_accessibility_shown_message">%s volume controls shown. Swipe up to dismiss.</string>
+    <string name="volume_dialog_accessibility_dismissed_message">Volume controls hidden</string>
+
     <!-- Name of special SystemUI debug settings -->
     <string name="system_ui_tuner">System UI Tuner</string>
 
@@ -1635,8 +1663,32 @@
     <!-- Warning message when we try to dock a non-resizeble tasks and launch it in fullscreen instead. -->
     <string name="dock_non_resizeble_failed_to_dock_text">App does not support split-screen.</string>
 
+    <!-- accessibility label for button to open settings [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_settings">Open settings.</string>
+
     <!-- accessibility label for button to expand quick settings [CHAR LIMIT=NONE] -->
-    <string name="accessibility_quick_settings_expand">Expand quick settings.</string>
+    <string name="accessibility_quick_settings_expand">Open quick settings.</string>
+
+    <!-- accessibility label for button to collapse quick settings [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_collapse">Close quick settings.</string>
+
+    <!-- accessibility label for alarm icon [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_alarm_set">Alarm set.</string>
+
+    <!-- accessibility label for button to select user [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_user">Signed in as <xliff:g name="user" example="John">%s</xliff:g></string>
+
+    <!-- accessibility label for no internet [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_no_internet">No internet.</string>
+
+    <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_open_details">Open details.</string>
+
+    <!-- accessibility label for quick settings items that open a details page [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_open_settings">Open <xliff:g name="page" example="Bluetooth">%s</xliff:g> settings.</string>
+
+    <!-- accessibility label for button to edit quick settings [CHAR LIMIT=NONE] -->
+    <string name="accessibility_quick_settings_edit">Edit order of settings.</string>
 
     <!-- accessibility label for paging indicator in quick settings [CHAR LIMITi=NONE] -->
     <string name="accessibility_quick_settings_page">Page <xliff:g name="current_page" example="1">%1$d</xliff:g> of <xliff:g name="num_pages" example="2">%2$d</xliff:g></string>
diff --git a/packages/SystemUI/src/com/android/systemui/DensityContainer.java b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
similarity index 66%
rename from packages/SystemUI/src/com/android/systemui/DensityContainer.java
rename to packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
index 2e3cb49..0afab88 100644
--- a/packages/SystemUI/src/com/android/systemui/DensityContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/AutoReinflateContainer.java
@@ -19,6 +19,7 @@
 import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.util.AttributeSet;
+import android.util.LocaleList;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.widget.FrameLayout;
@@ -26,31 +27,47 @@
 import java.util.ArrayList;
 import java.util.List;
 
-public class DensityContainer extends FrameLayout {
+/**
+ * Custom {@link FrameLayout} that re-inflates when changes to {@link Configuration} happen.
+ * Currently supports changes to density and locale.
+ */
+public class AutoReinflateContainer extends FrameLayout {
 
     private final List<InflateListener> mInflateListeners = new ArrayList<>();
     private final int mLayout;
     private int mDensity;
+    private LocaleList mLocaleList;
 
-    public DensityContainer(Context context, @Nullable AttributeSet attrs) {
+    public AutoReinflateContainer(Context context, @Nullable AttributeSet attrs) {
         super(context, attrs);
 
         mDensity = context.getResources().getConfiguration().densityDpi;
+        mLocaleList = context.getResources().getConfiguration().getLocales();
 
-        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DensityContainer);
-        if (!a.hasValue(R.styleable.DensityContainer_android_layout)) {
-            throw new IllegalArgumentException("DensityContainer must contain a layout");
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.AutoReinflateContainer);
+        if (!a.hasValue(R.styleable.AutoReinflateContainer_android_layout)) {
+            throw new IllegalArgumentException("AutoReinflateContainer must contain a layout");
         }
-        mLayout = a.getResourceId(R.styleable.DensityContainer_android_layout, 0);
+        mLayout = a.getResourceId(R.styleable.AutoReinflateContainer_android_layout, 0);
         inflateLayout();
     }
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
-        int density = newConfig.densityDpi;
+        boolean shouldInflateLayout = false;
+        final int density = newConfig.densityDpi;
         if (density != mDensity) {
             mDensity = density;
+            shouldInflateLayout = true;
+        }
+        final LocaleList localeList = newConfig.getLocales();
+        if (localeList != mLocaleList) {
+            mLocaleList = localeList;
+            shouldInflateLayout = true;
+        }
+
+        if (shouldInflateLayout) {
             inflateLayout();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 0bf81e9..d8b95cc 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -89,7 +89,8 @@
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         setContentDescription(
-                getContext().getString(R.string.accessibility_battery_level, level));
+                getContext().getString(charging ? R.string.accessibility_battery_level_charging
+                        : R.string.accessibility_battery_level, level));
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
index 5e35d76..851ab77 100644
--- a/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
+++ b/packages/SystemUI/src/com/android/systemui/classifier/HumanInteractionClassifier.java
@@ -67,7 +67,7 @@
         // If the phone is rotated to landscape, the calculations would be wrong if xdpi and ydpi
         // were to be used separately. Due negligible differences in xdpi and ydpi we can just
         // take the average.
-        // TODO: make this respect DPI changes.
+        // Note that xdpi and ydpi are the physical pixels per inch and are not affected by scaling.
         mDpi = (displayMetrics.xdpi + displayMetrics.ydpi) / 2.0f;
         mClassifierData = new ClassifierData(mDpi);
         mHistoryEvaluator = new HistoryEvaluator();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
index 9bc85c8..fb76918 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileQueryHelper.java
@@ -54,7 +54,7 @@
         // TODO: Live?
     }
 
-    private void addSystemTiles(QSTileHost host) {
+    private void addSystemTiles(final QSTileHost host) {
         String possible = mContext.getString(R.string.quick_settings_tiles_default)
                 + ",hotspot,inversion,saver,work,cast,night";
         String[] possibleTiles = possible.split(",");
@@ -93,7 +93,7 @@
                 mainHandler.post(new Runnable() {
                     @Override
                     public void run() {
-                        new QueryTilesTask().execute();
+                        new QueryTilesTask().execute(host.getTiles());
                     }
                 });
             }
@@ -133,9 +133,10 @@
         public boolean isSystem;
     }
 
-    private class QueryTilesTask extends AsyncTask<Void, Void, Collection<TileInfo>> {
+    private class QueryTilesTask extends
+            AsyncTask<Collection<QSTile<?>>, Void, Collection<TileInfo>> {
         @Override
-        protected Collection<TileInfo> doInBackground(Void... params) {
+        protected Collection<TileInfo> doInBackground(Collection<QSTile<?>>... params) {
             List<TileInfo> tiles = new ArrayList<>();
             PackageManager pm = mContext.getPackageManager();
             List<ResolveInfo> services = pm.queryIntentServicesAsUser(
@@ -143,7 +144,13 @@
             for (ResolveInfo info : services) {
                 String packageName = info.serviceInfo.packageName;
                 ComponentName componentName = new ComponentName(packageName, info.serviceInfo.name);
+                final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
                 String spec = CustomTile.toSpec(componentName);
+                State state = getState(params[0], spec);
+                if (state != null) {
+                    addTile(spec, appLabel, state, false);
+                    continue;
+                }
                 if (info.serviceInfo.icon == 0) {
                     continue;
                 }
@@ -157,12 +164,22 @@
                 icon.mutate();
                 icon.setTint(mContext.getColor(android.R.color.white));
                 CharSequence label = info.serviceInfo.loadLabel(pm);
-                final CharSequence appLabel = info.serviceInfo.applicationInfo.loadLabel(pm);
                 addTile(spec, icon, label != null ? label.toString() : "null", appLabel, mContext);
             }
             return tiles;
         }
 
+        private State getState(Collection<QSTile<?>> tiles, String spec) {
+            for (QSTile<?> tile : tiles) {
+                if (spec.equals(tile.getTileSpec())) {
+                    final QSTile.State state = tile.newTileState();
+                    tile.getState().copyTo(state);
+                    return state;
+                }
+            }
+            return null;
+        }
+
         @Override
         protected void onPostExecute(Collection<TileInfo> result) {
             mTiles.addAll(result);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index 630cb66..e117bfe 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -423,25 +423,26 @@
 
         int currentUser = sSystemServicesProxy.getCurrentUser();
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
+        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
         boolean screenPinningActive = ssp.isScreenPinningActive();
-        boolean isTopTaskHome = topTask != null && SystemServicesProxy.isHomeStack(topTask.stackId);
-        if (topTask != null && !isTopTaskHome && !screenPinningActive) {
-            logDockAttempt(mContext, topTask.topActivity, topTask.resizeMode);
-            if (topTask.isDockable) {
+        boolean isRunningTaskInHomeStack = runningTask != null &&
+                SystemServicesProxy.isHomeStack(runningTask.stackId);
+        if (runningTask != null && !isRunningTaskInHomeStack && !screenPinningActive) {
+            logDockAttempt(mContext, runningTask.topActivity, runningTask.resizeMode);
+            if (runningTask.isDockable) {
                 if (metricsDockAction != -1) {
                     MetricsLogger.action(mContext, metricsDockAction,
-                            topTask.topActivity.flattenToShortString());
+                            runningTask.topActivity.flattenToShortString());
                 }
                 if (sSystemServicesProxy.isSystemUser(currentUser)) {
-                    mImpl.dockTopTask(topTask.id, dragMode, stackCreateMode, initialBounds);
+                    mImpl.dockTopTask(runningTask.id, dragMode, stackCreateMode, initialBounds);
                 } else {
                     if (mSystemToUserCallbacks != null) {
                         IRecentsNonSystemUserCallbacks callbacks =
                                 mSystemToUserCallbacks.getNonSystemUserRecentsForUser(currentUser);
                         if (callbacks != null) {
                             try {
-                                callbacks.dockTopTask(topTask.id, dragMode, stackCreateMode,
+                                callbacks.dockTopTask(runningTask.id, dragMode, stackCreateMode,
                                         initialBounds);
                             } catch (RemoteException e) {
                                 Log.e(TAG, "Callback failed", e);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 2040833..54713d0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -26,6 +26,7 @@
 import android.content.res.Configuration;
 import android.net.Uri;
 import android.os.Bundle;
+import android.os.Handler;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -97,6 +98,7 @@
     public final static int INCOMPATIBLE_APP_ALPHA_DURATION = 150;
 
     private RecentsPackageMonitor mPackageMonitor;
+    private Handler mHandler = new Handler();
     private long mLastTabKeyEventTime;
     private int mLastDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
     private int mLastDisplayDensity;
@@ -138,12 +140,14 @@
         @Override
         public void run() {
             try {
-                ActivityOptions opts = mOpts;
-                if (opts == null) {
-                    opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
-                            R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit);
-                }
-                startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+                mHandler.post(() -> {
+                    ActivityOptions opts = mOpts;
+                    if (opts == null) {
+                        opts = ActivityOptions.makeCustomAnimation(RecentsActivity.this,
+                                R.anim.recents_to_launcher_enter, R.anim.recents_to_launcher_exit);
+                    }
+                    startActivityAsUser(mLaunchIntent, opts.toBundle(), UserHandle.CURRENT);
+                });
             } catch (Exception e) {
                 Log.e(TAG, getString(R.string.recents_launch_error_message, "Home"), e);
             }
@@ -169,7 +173,7 @@
      */
     boolean dismissRecentsToFocusedTask(int logCategory) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask(logCategory)) return true;
         }
@@ -181,7 +185,7 @@
      */
     boolean dismissRecentsToLaunchTargetTaskOrHome() {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchPreviousTask()) return true;
             // If none of the other cases apply, then just go Home
@@ -195,7 +199,7 @@
      */
     boolean dismissRecentsToFocusedTaskOrHome() {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask(0 /* logCategory */)) return true;
             // If none of the other cases apply, then just go Home
@@ -223,20 +227,15 @@
                 new DismissRecentsToHomeAnimationStarted(animateTaskViews);
         dismissEvent.addPostAnimationCallback(new LaunchHomeRunnable(mHomeIntent,
                 overrideAnimation));
-        dismissEvent.addPostAnimationCallback(new Runnable() {
-            @Override
-            public void run() {
-                Recents.getSystemServices().sendCloseSystemWindows(
-                        BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
-            }
-        });
+        Recents.getSystemServices().sendCloseSystemWindows(
+                BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
         EventBus.getDefault().send(dismissEvent);
     }
 
     /** Dismisses Recents directly to Home if we currently aren't transitioning. */
     boolean dismissRecentsToHomeIfVisible(boolean animated) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // Return to Home
             dismissRecentsToHome(animated);
             return true;
@@ -448,7 +447,7 @@
         RecentsActivityLaunchState launchState = config.getLaunchState();
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan loadPlan = loader.createLoadPlan(this);
-        loader.preloadTasks(loadPlan, -1 /* topTaskId */, false /* isTopTaskHome */);
+        loader.preloadTasks(loadPlan, -1 /* runningTaskId */, false /* isHomeStackVisible */);
 
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
         loadOpts.numVisibleTasks = launchState.launchedNumVisibleTasks;
@@ -777,6 +776,7 @@
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         super.dump(prefix, fd, writer, args);
         EventBus.getDefault().dump(prefix, writer);
+        Recents.getTaskLoader().dump(prefix, writer);
 
         String id = Integer.toHexString(System.identityHashCode(this));
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index f961390..cf18c41 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -108,11 +108,11 @@
             if (config.svelteLevel == RecentsConfiguration.SVELTE_NONE) {
                 RecentsTaskLoader loader = Recents.getTaskLoader();
                 SystemServicesProxy ssp = Recents.getSystemServices();
-                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
+                ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
 
                 // Load the next task only if we aren't svelte
                 RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-                loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
+                loader.preloadTasks(plan, -1, true /* isHomeStackVisible */);
                 RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
                 // This callback is made when a new activity is launched and the old one is paused
                 // so ignore the current activity and try and preload the thumbnail for the
@@ -189,7 +189,7 @@
         // We can use a new plan since the caches will be the same.
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
+        loader.preloadTasks(plan, -1, true /* isHomeStackVisible */);
         RecentsTaskLoadPlan.Options launchOpts = new RecentsTaskLoadPlan.Options();
         launchOpts.numVisibleTasks = loader.getIconCacheSize();
         launchOpts.numVisibleTaskThumbnails = loader.getThumbnailCacheSize();
@@ -262,10 +262,11 @@
         try {
             // Check if the top task is in the home stack, and start the recents activity
             SystemServicesProxy ssp = Recents.getSystemServices();
-            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
-            MutableBoolean isTopTaskHome = new MutableBoolean(true);
-            if (topTask == null || !ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
-                startRecentsActivity(topTask, isTopTaskHome.value || fromHome, animate, growTarget);
+            MutableBoolean isHomeStackVisible = new MutableBoolean(false);
+            if (!ssp.isRecentsActivityVisible(isHomeStackVisible)) {
+                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+                startRecentsActivity(runningTask, isHomeStackVisible.value || fromHome, animate,
+                        growTarget);
             }
         } catch (ActivityNotFoundException e) {
             Log.e(TAG, "Failed to launch RecentsActivity", e);
@@ -301,11 +302,10 @@
 
         try {
             SystemServicesProxy ssp = Recents.getSystemServices();
-            ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
-            MutableBoolean isTopTaskHome = new MutableBoolean(true);
+            MutableBoolean isHomeStackVisible = new MutableBoolean(true);
             long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
 
-            if (topTask != null && ssp.isRecentsTopMost(topTask, isTopTaskHome)) {
+            if (ssp.isRecentsActivityVisible(isHomeStackVisible)) {
                 RecentsDebugFlags debugFlags = Recents.getDebugFlags();
                 RecentsConfiguration config = Recents.getConfiguration();
                 RecentsActivityLaunchState launchState = config.getLaunchState();
@@ -343,7 +343,9 @@
                 }
 
                 // Otherwise, start the recents activity
-                startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */, growTarget);
+                ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
+                startRecentsActivity(runningTask, isHomeStackVisible.value, true /* animate */,
+                        growTarget);
 
                 // Only close the other system windows if we are actually showing recents
                 ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
@@ -358,18 +360,18 @@
         // Preload only the raw task list into a new load plan (which will be consumed by the
         // RecentsActivity) only if there is a task to animate to.
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ActivityManager.RunningTaskInfo topTask = ssp.getTopMostTask();
-        MutableBoolean topTaskHome = new MutableBoolean(true);
-        if (topTask != null && !ssp.isRecentsTopMost(topTask, topTaskHome)) {
+        MutableBoolean isHomeStackVisible = new MutableBoolean(true);
+        if (!ssp.isRecentsActivityVisible(isHomeStackVisible)) {
+            ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
             RecentsTaskLoader loader = Recents.getTaskLoader();
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
-            sInstanceLoadPlan.preloadRawTasks(topTaskHome.value);
-            loader.preloadTasks(sInstanceLoadPlan, topTask.id, topTaskHome.value);
+            sInstanceLoadPlan.preloadRawTasks(isHomeStackVisible.value);
+            loader.preloadTasks(sInstanceLoadPlan, runningTask.id, isHomeStackVisible.value);
             TaskStack stack = sInstanceLoadPlan.getTaskStack();
             if (stack.getTaskCount() > 0) {
                 // Only preload the icon (but not the thumbnail since it may not have been taken for
                 // the pausing activity)
-                preloadIcon(topTask);
+                preloadIcon(runningTask);
 
                 // At this point, we don't know anything about the stack state.  So only calculate
                 // the dimensions of the thumbnail that we need for the transition into Recents, but
@@ -398,25 +400,25 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
+        loader.preloadTasks(plan, -1, true /* isHomeStackVisible */);
         TaskStack focusedStack = plan.getTaskStack();
 
         // Return early if there are no tasks in the focused stack
         if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
-        ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
         // Return early if there is no running task
+        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
         if (runningTask == null) return;
 
         // Find the task in the recents list
-        boolean isTopTaskHome = SystemServicesProxy.isHomeStack(runningTask.stackId);
+        boolean isRunningTaskInHomeStack = SystemServicesProxy.isHomeStack(runningTask.stackId);
         ArrayList<Task> tasks = focusedStack.getStackTasks();
         Task toTask = null;
         ActivityOptions launchOpts = null;
         int taskCount = tasks.size();
         for (int i = taskCount - 1; i >= 1; i--) {
             Task task = tasks.get(i);
-            if (isTopTaskHome) {
+            if (isRunningTaskInHomeStack) {
                 toTask = tasks.get(i - 1);
                 launchOpts = ActivityOptions.makeCustomAnimation(mContext,
                         R.anim.recents_launch_next_affiliated_task_target,
@@ -450,14 +452,14 @@
         SystemServicesProxy ssp = Recents.getSystemServices();
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsTaskLoadPlan plan = loader.createLoadPlan(mContext);
-        loader.preloadTasks(plan, -1, true /* isTopTaskHome */);
+        loader.preloadTasks(plan, -1, true /* isHomeStackVisible */);
         TaskStack focusedStack = plan.getTaskStack();
 
         // Return early if there are no tasks in the focused stack
         if (focusedStack == null || focusedStack.getTaskCount() == 0) return;
 
-        ActivityManager.RunningTaskInfo runningTask = ssp.getTopMostTask();
         // Return early if there is no running task (can't determine affiliated tasks in this case)
+        ActivityManager.RunningTaskInfo runningTask = ssp.getRunningTask();
         if (runningTask == null) return;
         // Return early if the running task is in the home stack (optimization)
         if (SystemServicesProxy.isHomeStack(runningTask.stackId)) return;
@@ -586,6 +588,7 @@
      */
     private void updateHeaderBarLayout(TaskStack stack, Rect windowRectOverride) {
         SystemServicesProxy ssp = Recents.getSystemServices();
+        Rect displayRect = ssp.getDisplayRect();
         Rect systemInsets = new Rect();
         ssp.getStableInsets(systemInsets);
         Rect windowRect = windowRectOverride != null
@@ -606,10 +609,10 @@
         // Rebind the header bar and draw it for the transition
         stackLayout.setSystemInsets(systemInsets);
         if (stack != null) {
-            stackLayout.getTaskStackBounds(windowRect, systemInsets.top, systemInsets.right,
-                    mTaskStackBounds);
+            stackLayout.getTaskStackBounds(displayRect, windowRect, systemInsets.top,
+                    systemInsets.right, mTaskStackBounds);
             stackLayout.reset();
-            stackLayout.initialize(windowRect, mTaskStackBounds,
+            stackLayout.initialize(displayRect, windowRect, mTaskStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(stack));
             mDummyStackView.setTasks(stack, false /* allowNotifyStackChanges */);
 
@@ -693,9 +696,9 @@
      * Creates the activity options for an app->recents transition.
      */
     private ActivityOptions getThumbnailTransitionActivityOptions(
-            ActivityManager.RunningTaskInfo topTask, TaskStackView stackView,
-            Rect windowOverrideRect) {
-        if (topTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
+            ActivityManager.RunningTaskInfo runningTask, TaskStackView stackView,
+                    Rect windowOverrideRect) {
+        if (runningTask.stackId == FREEFORM_WORKSPACE_STACK_ID) {
             ArrayList<AppTransitionAnimationSpec> specs = new ArrayList<>();
             ArrayList<Task> tasks = stackView.getStack().getStackTasks();
             TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
@@ -801,8 +804,8 @@
     /**
      * Shows the recents activity
      */
-    protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-            boolean isTopTaskHome, boolean animate, int growTarget) {
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
+            boolean isHomeStackVisible, boolean animate, int growTarget) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
         RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
 
@@ -814,24 +817,24 @@
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
         }
         if (mLaunchedWhileDocking || mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
-            loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
+            loader.preloadTasks(sInstanceLoadPlan, runningTask.id, isHomeStackVisible);
         }
 
         TaskStack stack = sInstanceLoadPlan.getTaskStack();
         boolean hasRecentTasks = stack.getTaskCount() > 0;
-        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
+        boolean useThumbnailTransition = (runningTask != null) && !isHomeStackVisible && hasRecentTasks;
 
         // Update the launch state that we need in updateHeaderBarLayout()
         launchState.launchedFromHome = !useThumbnailTransition;
         launchState.launchedFromApp = useThumbnailTransition || mLaunchedWhileDocking;
         launchState.launchedViaDockGesture = mLaunchedWhileDocking;
         launchState.launchedViaDragGesture = mDraggingInRecents;
-        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        launchState.launchedToTaskId = (runningTask != null) ? runningTask.id : -1;
         launchState.launchedWithAltTab = mTriggeredFromAltTab;
 
         // Preload the icon (this will be a null-op if we have preloaded the icon already in
         // preloadRecents())
-        preloadIcon(topTask);
+        preloadIcon(runningTask);
 
         // Update the header bar if necessary
         Rect windowOverrideRect = getWindowRectOverride(growTarget);
@@ -853,7 +856,7 @@
         ActivityOptions opts;
         if (useThumbnailTransition) {
             // Try starting with a thumbnail transition
-            opts = getThumbnailTransitionActivityOptions(topTask, mDummyStackView,
+            opts = getThumbnailTransitionActivityOptions(runningTask, mDummyStackView,
                     windowOverrideRect);
         } else {
             // If there is no thumbnail transition, but is launching from home into recents, then
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 6f1a69c..be06ad0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -38,7 +38,6 @@
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ResolveInfo;
-import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
@@ -251,9 +250,14 @@
         return sSystemServicesProxy;
     }
 
-    /** Returns a list of the recents tasks */
+    /**
+     * Returns a list of the recents tasks.
+     *
+     * @param isHomeStackVisible whether or not the home stack is currently visible.  If it is
+     *                           visible, then we ignore all excluded tasks (even the first one).
+     */
     public List<ActivityManager.RecentTaskInfo> getRecentTasks(int numLatestTasks, int userId,
-            boolean isTopTaskHome, ArraySet<Integer> quietProfileIds) {
+            boolean isHomeStackVisible, ArraySet<Integer> quietProfileIds) {
         if (mAm == null) return null;
 
         // If we are mocking, then create some recent tasks
@@ -320,7 +324,7 @@
             boolean isBlackListed = sRecentsBlacklist.contains(t.realActivity.getClassName());
             // Filter out recent tasks from managed profiles which are in quiet mode.
             isExcluded |= quietProfileIds.contains(t.userId);
-            if (isBlackListed || (isExcluded && (isTopTaskHome || !isFirstValidTask))) {
+            if (isBlackListed || (isExcluded && (isHomeStackVisible || !isFirstValidTask))) {
                 iter.remove();
                 continue;
             }
@@ -330,15 +334,11 @@
         return tasks.subList(0, Math.min(tasks.size(), numLatestTasks));
     }
 
-    /** Returns a list of the running tasks */
-    private List<ActivityManager.RunningTaskInfo> getRunningTasks(int numTasks) {
-        if (mAm == null) return null;
-        return mAm.getRunningTasks(numTasks);
-    }
-
-    /** Returns the top task. */
-    public ActivityManager.RunningTaskInfo getTopMostTask() {
-        List<ActivityManager.RunningTaskInfo> tasks = getRunningTasks(1);
+    /**
+     * Returns the top running task.
+     */
+    public ActivityManager.RunningTaskInfo getRunningTask() {
+        List<ActivityManager.RunningTaskInfo> tasks = mAm.getRunningTasks(1);
         if (tasks != null && !tasks.isEmpty()) {
             return tasks.get(0);
         }
@@ -346,6 +346,39 @@
     }
 
     /**
+     * Returns whether the recents activity is currently visible.
+     */
+    public boolean isRecentsActivityVisible() {
+        return isRecentsActivityVisible(null);
+    }
+
+    /**
+     * Returns whether the recents activity is currently visible.
+     *
+     * @param isHomeStackVisible if provided, will return whether the home stack is visible
+     *                           regardless of the recents visibility
+     */
+    public boolean isRecentsActivityVisible(MutableBoolean isHomeStackVisible) {
+        if (mIam == null) return false;
+
+        try {
+            ActivityManager.StackInfo stackInfo = mIam.getStackInfo(
+                    ActivityManager.StackId.HOME_STACK_ID);
+            ComponentName topActivity = stackInfo.topActivity;
+            if (isHomeStackVisible != null) {
+                isHomeStackVisible.value = stackInfo.visible;
+            }
+            return (stackInfo.visible && topActivity != null
+                    && topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE)
+                    && (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY)
+                        || topActivity.getClassName().equals(RecentsTvImpl.RECENTS_TV_ACTIVITY)));
+        } catch (RemoteException e) {
+            e.printStackTrace();
+        }
+        return false;
+    }
+
+    /**
      * Returns whether this device has freeform workspaces.
      */
     public boolean hasFreeformWorkspaceSupport() {
@@ -359,56 +392,6 @@
         return mIsSafeMode;
     }
 
-    /** Returns whether the recents is currently running */
-    public boolean isRecentsTopMost(ActivityManager.RunningTaskInfo topTask,
-            MutableBoolean isHomeTopMost) {
-        if (topTask != null) {
-            ComponentName topActivity = topTask.topActivity;
-
-            // Check if the front most activity is recents
-            if ((topActivity.getPackageName().equals(RecentsImpl.RECENTS_PACKAGE) &&
-                    (topActivity.getClassName().equals(RecentsImpl.RECENTS_ACTIVITY) ||
-                    topActivity.getClassName().equals(RecentsTvImpl.RECENTS_TV_ACTIVITY)))) {
-                if (isHomeTopMost != null) {
-                    isHomeTopMost.value = false;
-                }
-                return true;
-            }
-
-            // Note, this is only valid because we currently only allow the recents and home
-            // activities in the home stack
-            if (isHomeTopMost != null) {
-                isHomeTopMost.value = SystemServicesProxy.isHomeStack(topTask.stackId);
-            }
-        }
-        return false;
-    }
-
-    /** Get the bounds of a task. */
-    public Rect getTaskBounds(int taskId) {
-        if (mIam == null) return null;
-
-        try {
-            return mIam.getTaskBounds(taskId);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
-        return null;
-    }
-
-    /**
-     * Resizes the given task to the new bounds.
-     */
-    public void resizeTask(int taskId, Rect bounds) {
-        if (mIam == null) return;
-
-        try {
-            mIam.resizeTask(taskId, bounds, ActivityManager.RESIZE_MODE_FORCED);
-        } catch (RemoteException e) {
-            e.printStackTrace();
-        }
-    }
-
     /** Docks a task to the side of the screen and starts it. */
     public void startTaskInDockedMode(int taskId, int createMode) {
         if (mIam == null) return;
@@ -439,18 +422,6 @@
         return false;
     }
 
-    /** Returns the focused stack id. */
-    public int getFocusedStack() {
-        if (mIam == null) return -1;
-
-        try {
-            return mIam.getFocusedStackId();
-        } catch (RemoteException e) {
-            e.printStackTrace();
-            return -1;
-        }
-    }
-
     /**
      * Returns whether the given stack id is the home stack id.
      */
@@ -516,6 +487,16 @@
     }
 
     /**
+     * Returns whether the device has a transposed nav bar (on the right of the screen) in the
+     * current display orientation.
+     */
+    public boolean hasTransposedNavigationBar() {
+        Rect insets = new Rect();
+        getStableInsets(insets);
+        return insets.right > 0;
+    }
+
+    /**
      * Cancels the current window transtion to/from Recents for the given task id.
      */
     public void cancelWindowTransition(int taskId) {
@@ -613,19 +594,6 @@
         }
     }
 
-    /** Moves a task to the front with the specified activity options. */
-    public void moveTaskToFront(int taskId, ActivityOptions opts) {
-        if (mAm == null) return;
-        if (RecentsDebugFlags.Static.EnableMockTasks) return;
-
-        if (opts != null) {
-            mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME,
-                    opts.toBundle());
-        } else {
-            mAm.moveTaskToFront(taskId, ActivityManager.MOVE_TASK_WITH_HOME);
-        }
-    }
-
     /** Removes the task */
     public void removeTask(final int taskId) {
         if (mAm == null) return;
@@ -1082,16 +1050,6 @@
         }
     }
 
-    /**
-     * Returns whether the device has a transposed nav bar (on the right of the screen) in the
-     * current display orientation.
-     */
-    public boolean hasTransposedNavBar() {
-        Rect insets = new Rect();
-        getStableInsets(insets);
-        return insets.right > 0;
-    }
-
     private final class H extends Handler {
         private static final int ON_TASK_STACK_CHANGED = 1;
         private static final int ON_ACTIVITY_PINNED = 2;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index af1628b..3979095 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -100,12 +100,12 @@
      * An optimization to preload the raw list of tasks. The raw tasks are saved in least-recent
      * to most-recent order.
      */
-    public synchronized void preloadRawTasks(boolean isTopTaskHome) {
+    public synchronized void preloadRawTasks(boolean isHomeStackVisible) {
         int currentUserId = UserHandle.USER_CURRENT;
         updateCurrentQuietProfilesCache(currentUserId);
         SystemServicesProxy ssp = Recents.getSystemServices();
         mRawTasks = ssp.getRecentTasks(ActivityManager.getMaxRecentTasksStatic(),
-                currentUserId, isTopTaskHome, mCurrentQuietProfiles);
+                currentUserId, isHomeStackVisible, mCurrentQuietProfiles);
 
         // Since the raw tasks are given in most-recent to least-recent order, we need to reverse it
         Collections.reverse(mRawTasks);
@@ -120,12 +120,12 @@
      * - least-recent to most-recent stack tasks
      * - least-recent to most-recent freeform tasks
      */
-    public synchronized void preloadPlan(RecentsTaskLoader loader, int topTaskId,
-            boolean isTopTaskHome) {
+    public synchronized void preloadPlan(RecentsTaskLoader loader, int runningTaskId,
+            boolean isHomeStackVisible) {
         Resources res = mContext.getResources();
         ArrayList<Task> allTasks = new ArrayList<>();
         if (mRawTasks == null) {
-            preloadRawTasks(isTopTaskHome);
+            preloadRawTasks(isHomeStackVisible);
         }
 
         SparseArray<Task.TaskKey> affiliatedTasks = new SparseArray<>();
@@ -182,7 +182,7 @@
             boolean isFreeformTask = SystemServicesProxy.isFreeformStack(t.stackId);
             boolean isStackTask = isFreeformTask || (!isHistoricalTask(t) ||
                     (t.lastActiveTime >= lastStackActiveTime && i >= (taskCount - MIN_NUM_TASKS)));
-            boolean isLaunchTarget = taskKey.id == topTaskId;
+            boolean isLaunchTarget = taskKey.id == runningTaskId;
             if (isStackTask && newLastStackActiveTime < 0) {
                 newLastStackActiveTime = t.lastActiveTime;
             }
@@ -196,7 +196,7 @@
             Drawable icon = isStackTask
                     ? loader.getAndUpdateActivityIcon(taskKey, t.taskDescription, res, false)
                     : null;
-            Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false);
+            Bitmap thumbnail = loader.getAndUpdateThumbnail(taskKey, false /* loadIfNotCached */);
             int activityColor = loader.getActivityPrimaryColor(t.taskDescription);
             int backgroundColor = loader.getActivityBackgroundColor(t.taskDescription);
             boolean isSystemApp = (info != null) &&
@@ -256,7 +256,8 @@
             if (opts.loadThumbnails && (isRunningTask || isVisibleThumbnail)) {
                 if (task.thumbnail == null || isRunningTask) {
                     if (config.svelteLevel <= RecentsConfiguration.SVELTE_LIMIT_CACHE) {
-                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey, true);
+                        task.thumbnail = loader.getAndUpdateThumbnail(taskKey,
+                                true /* loadIfNotCached */);
                     } else if (config.svelteLevel == RecentsConfiguration.SVELTE_DISABLE_CACHE) {
                         loadQueue.addTask(task);
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index fb92971..9460b64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -36,7 +36,9 @@
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.events.activity.PackagesChangedEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
+import com.android.systemui.recents.misc.Utilities;
 
+import java.io.PrintWriter;
 import java.util.Map;
 import java.util.concurrent.ConcurrentLinkedQueue;
 
@@ -331,8 +333,9 @@
     }
 
     /** Preloads recents tasks using the specified plan to store the output. */
-    public void preloadTasks(RecentsTaskLoadPlan plan, int topTaskId, boolean isTopTaskHome) {
-        plan.preloadPlan(this, topTaskId, isTopTaskHome);
+    public void preloadTasks(RecentsTaskLoadPlan plan, int runningTaskId,
+            boolean isHomeStackVisible) {
+        plan.preloadPlan(this, runningTaskId, isHomeStackVisible);
     }
 
     /** Begins loading the heavy task data according to the specified options. */
@@ -624,4 +627,14 @@
             }
         }
     }
+
+    public void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+
+        writer.print(prefix); writer.println(TAG);
+        writer.print(prefix); writer.println("Icon Cache");
+        mIconCache.dump(innerPrefix, writer);
+        writer.print(prefix); writer.println("Thumbnail Cache");
+        mThumbnailCache.dump(innerPrefix, writer);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
index 68c46a9..c6528a1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -338,9 +338,18 @@
 
     public void dump(String prefix, PrintWriter writer) {
         writer.print(prefix); writer.print(key);
-        if (affiliationTaskId != key.id) {
+        if (isAffiliatedTask()) {
             writer.print(" "); writer.print("affTaskId=" + affiliationTaskId);
         }
+        if (!isDockable) {
+            writer.print(" dockable=N");
+        }
+        if (isLaunchTarget) {
+            writer.print(" launchTarget=Y");
+        }
+        if (isFreeformTask()) {
+            writer.print(" freeform=Y");
+        }
         writer.print(" "); writer.print(title);
         writer.println();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
index 748d8ed..c63a494 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskKeyLruCache.java
@@ -20,6 +20,9 @@
 import android.util.LruCache;
 import android.util.SparseArray;
 
+import java.io.PrintWriter;
+import java.util.ArrayList;
+
 /**
  * A mapping of {@link Task.TaskKey} to value, with additional LRU functionality where the least
  * recently referenced key/values will be evicted as more values than the given cache size are
@@ -112,4 +115,16 @@
     final void trimToSize(int cacheSize) {
         mCache.trimToSize(cacheSize);
     }
+
+    public void dump(String prefix, PrintWriter writer) {
+        String innerPrefix = prefix + "  ";
+
+        writer.print(prefix); writer.print(TAG);
+        writer.print(" numEntries="); writer.print(mKeys.size());
+        writer.println();
+        int keyCount = mKeys.size();
+        for (int i = 0; i < keyCount; i++) {
+            writer.print(innerPrefix); writer.println(mKeys.get(mKeys.keyAt(i)));
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
index 47995c4..f42eea3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -49,6 +49,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.internal.policy.DockedDividerUtils;
+import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
 import com.android.systemui.recents.RecentsDebugFlags;
@@ -253,7 +254,7 @@
         private static final int HORIZONTAL = 0;
         private static final int VERTICAL = 1;
 
-        private static final int DOCK_AREA_ALPHA = 192;
+        private static final int DOCK_AREA_ALPHA = 80;
         public static final DockState NONE = new DockState(DOCKED_INVALID, -1, 80, 255, HORIZONTAL,
                 null, null, null);
         public static final DockState LEFT = new DockState(DOCKED_LEFT,
@@ -368,19 +369,28 @@
                     mDockAreaOverlayAnimator.cancel();
                 }
 
+                ObjectAnimator anim;
                 ArrayList<Animator> animators = new ArrayList<>();
                 if (dockAreaOverlay.getAlpha() != areaAlpha) {
                     if (animateAlpha) {
-                        animators.add(ObjectAnimator.ofInt(dockAreaOverlay,
-                                Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha));
+                        anim = ObjectAnimator.ofInt(dockAreaOverlay,
+                                Utilities.DRAWABLE_ALPHA, dockAreaOverlay.getAlpha(), areaAlpha);
+                        anim.setDuration(duration);
+                        anim.setInterpolator(interpolator);
+                        animators.add(anim);
                     } else {
                         dockAreaOverlay.setAlpha(areaAlpha);
                     }
                 }
                 if (mHintTextAlpha != hintAlpha) {
                     if (animateAlpha) {
-                        animators.add(ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
-                                hintAlpha));
+                        anim = ObjectAnimator.ofInt(this, HINT_ALPHA, mHintTextAlpha,
+                                hintAlpha);
+                        anim.setDuration(150);
+                        anim.setInterpolator(hintAlpha > mHintTextAlpha
+                                ? Interpolators.ALPHA_IN
+                                : Interpolators.ALPHA_OUT);
+                        animators.add(anim);
                     } else {
                         mHintTextAlpha = hintAlpha;
                         dockAreaOverlay.invalidateSelf();
@@ -390,8 +400,11 @@
                     if (animateBounds) {
                         PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
                                 Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
-                                dockAreaOverlay.getBounds(), bounds);
-                        animators.add(ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop));
+                                new Rect(dockAreaOverlay.getBounds()), bounds);
+                        anim = ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop);
+                        anim.setDuration(duration);
+                        anim.setInterpolator(interpolator);
+                        animators.add(anim);
                     } else {
                         dockAreaOverlay.setBounds(bounds);
                     }
@@ -399,8 +412,6 @@
                 if (!animators.isEmpty()) {
                     mDockAreaOverlayAnimator = new AnimatorSet();
                     mDockAreaOverlayAnimator.playTogether(animators);
-                    mDockAreaOverlayAnimator.setDuration(duration);
-                    mDockAreaOverlayAnimator.setInterpolator(interpolator);
                     mDockAreaOverlayAnimator.start();
                 }
             }
@@ -481,8 +492,9 @@
          * Returns the task stack bounds with the given {@param width} and
          * {@param height}.
          */
-        public Rect getDockedTaskStackBounds(int width, int height, int dividerSize, Rect insets,
-                TaskStackLayoutAlgorithm layoutAlgorithm, Resources res, Rect windowRectOut) {
+        public Rect getDockedTaskStackBounds(Rect displayRect, int width, int height,
+                int dividerSize, Rect insets, TaskStackLayoutAlgorithm layoutAlgorithm,
+                Resources res, Rect windowRectOut) {
             // Calculate the inverse docked task bounds
             boolean isHorizontalDivision =
                     res.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;
@@ -499,7 +511,8 @@
             int top = dockArea.bottom < 1f
                     ? 0
                     : insets.top;
-            layoutAlgorithm.getTaskStackBounds(windowRectOut, top, insets.right, taskStackBounds);
+            layoutAlgorithm.getTaskStackBounds(displayRect, windowRectOut, top, insets.right,
+                    taskStackBounds);
             return taskStackBounds;
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
index 7378102..9dc9c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -26,6 +26,7 @@
 import android.view.View;
 import android.view.ViewTreeObserver.OnPreDrawListener;
 import android.view.WindowManager;
+import android.view.accessibility.AccessibilityEvent;
 import android.widget.FrameLayout.LayoutParams;
 
 import com.android.systemui.R;
@@ -131,6 +132,7 @@
                 @Override
                 public void onRecentsFocused() {
                     mRecentsView.requestFocus();
+                    mRecentsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
                 }
             };
     private final View.OnFocusChangeListener mPipViewFocusChangeListener =
@@ -215,7 +217,7 @@
 
     boolean dismissRecentsToLaunchTargetTaskOrHome(boolean animate) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchPreviousTask(animate)) {
               return true;
@@ -228,7 +230,7 @@
 
     boolean dismissRecentsToFocusedTaskOrHome() {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // If we have a focused Task, launch that Task now
             if (mRecentsView.launchFocusedTask()) return true;
             // If none of the other cases apply, then just go Home
@@ -261,7 +263,7 @@
 
     boolean dismissRecentsToHomeIfVisible(boolean animated) {
         SystemServicesProxy ssp = Recents.getSystemServices();
-        if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
+        if (ssp.isRecentsActivityVisible()) {
             // Return to Home
             dismissRecentsToHome(animated);
             return true;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
index 18b9263..59ea358 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvImpl.java
@@ -48,8 +48,8 @@
     }
 
     @Override
-    protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
-            boolean isTopTaskHome, boolean animate, int growTarget) {
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
+            boolean isHomeStackVisible, boolean animate, int growTarget) {
         RecentsTaskLoader loader = Recents.getTaskLoader();
 
         // In the case where alt-tab is triggered, we never get a preloadRecents() call, so we
@@ -60,25 +60,25 @@
             sInstanceLoadPlan = loader.createLoadPlan(mContext);
         }
         if (mTriggeredFromAltTab || !sInstanceLoadPlan.hasTasks()) {
-            loader.preloadTasks(sInstanceLoadPlan, topTask.id, isTopTaskHome);
+            loader.preloadTasks(sInstanceLoadPlan, runningTask.id, isHomeStackVisible);
         }
         TaskStack stack = sInstanceLoadPlan.getTaskStack();
 
         if (!animate) {
             ActivityOptions opts = ActivityOptions.makeCustomAnimation(mContext, -1, -1);
-            startRecentsActivity(topTask, opts, false /* fromHome */, false /* fromThumbnail*/);
+            startRecentsActivity(runningTask, opts, false /* fromHome */, false /* fromThumbnail*/);
             return;
         }
 
         boolean hasRecentTasks = stack.getTaskCount() > 0;
-        boolean useThumbnailTransition = (topTask != null) && !isTopTaskHome && hasRecentTasks;
+        boolean useThumbnailTransition = (runningTask != null) && !isHomeStackVisible && hasRecentTasks;
 
         if (useThumbnailTransition) {
             // Try starting with a thumbnail transition
-            ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(topTask,
+            ActivityOptions opts = getThumbnailTransitionActivityOptionsForTV(runningTask,
                     stack.getTaskCount());
             if (opts != null) {
-                startRecentsActivity(topTask, opts, false /* fromHome */, true /* fromThumbnail */);
+                startRecentsActivity(runningTask, opts, false /* fromHome */, true /* fromThumbnail */);
             } else {
                 // Fall through below to the non-thumbnail transition
                 useThumbnailTransition = false;
@@ -86,19 +86,19 @@
         }
 
         if (!useThumbnailTransition) {
-            startRecentsActivity(topTask, null, true /* fromHome */, false /* fromThumbnail */);
+            startRecentsActivity(runningTask, null, true /* fromHome */, false /* fromThumbnail */);
         }
         mLastToggleTime = SystemClock.elapsedRealtime();
     }
 
-    protected void startRecentsActivity(ActivityManager.RunningTaskInfo topTask,
+    protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
             ActivityOptions opts, boolean fromHome, boolean fromThumbnail) {
         // Update the configuration based on the launch options
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         launchState.launchedFromHome = fromHome;
         launchState.launchedFromApp = fromThumbnail;
-        launchState.launchedToTaskId = (topTask != null) ? topTask.id : -1;
+        launchState.launchedToTaskId = (runningTask != null) ? runningTask.id : -1;
         launchState.launchedWithAltTab = mTriggeredFromAltTab;
 
         Intent intent = new Intent();
@@ -119,10 +119,10 @@
      * Creates the activity options for an app->recents transition on TV.
      */
     private ActivityOptions getThumbnailTransitionActivityOptionsForTV(
-            ActivityManager.RunningTaskInfo topTask, int numTasks) {
+            ActivityManager.RunningTaskInfo runningTask, int numTasks) {
         Rect rect = TaskCardView.getStartingCardThumbnailRect(mContext, numTasks);
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ThumbnailData thumbnailData = ssp.getTaskThumbnail(topTask.id);
+        ThumbnailData thumbnailData = ssp.getTaskThumbnail(runningTask.id);
         if (thumbnailData.thumbnail != null) {
             Bitmap thumbnail = Bitmap.createScaledBitmap(thumbnailData.thumbnail, rect.width(),
                     rect.height(), false);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index be69552..c3efe64 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -36,6 +36,7 @@
     private final float mSelectedZDelta;
     private final float mUnselectedSpacing;
     private final float mSelectedSpacingDelta;
+    private final float mDismissIconAlpha;
     private final int mAnimDuration;
     private final Interpolator mFocusInterpolator;
 
@@ -71,6 +72,8 @@
         mFocusAnimation.setDuration(mAnimDuration);
         mFocusAnimation.setInterpolator(mFocusInterpolator);
 
+        mDismissIconAlpha = res.getFloat(R.integer.dismiss_unselected_alpha);
+
         setFocusProgress(0.0f);
 
         mFocusAnimation.addListener(new AnimatorListenerAdapter() {
@@ -99,7 +102,7 @@
         mTargetView.setPadding((int) spacing, mTargetView.getPaddingTop(),
                 (int) spacing, mTargetView.getPaddingBottom());
 
-
+        mTargetView.getDismissIconView().setAlpha(mDismissIconAlpha * level);
         mTargetView.getThumbnailView().setZ(z);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index 235b782..ef8a54b7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -47,6 +47,7 @@
 
     private static final String TAG = "TaskCardView";
     private View mThumbnailView;
+    private View mDismissIconView;
     private TextView mTitleTextView;
     private ImageView mBadgeView;
     private Task mTask;
@@ -78,6 +79,7 @@
         mThumbnailView = findViewById(R.id.card_view_thumbnail);
         mTitleTextView = (TextView) findViewById(R.id.card_title_text);
         mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
+        mDismissIconView = findViewById(R.id.dismiss_icon);
         mDismissAnimationsHolder = new DismissAnimationsHolder(this);
         View title = findViewById(R.id.card_info_field);
         mCornerRadius = getResources().getDimensionPixelSize(
@@ -316,4 +318,8 @@
     public View getThumbnailView() {
         return mThumbnailView;
     }
+
+    public View getDismissIconView() {
+        return mDismissIconView;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
index 48e1370..5e87e2a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/AnimationProps.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
+import android.animation.ValueAnimator;
 import android.annotation.IntDef;
 import android.util.SparseArray;
 import android.util.SparseLongArray;
@@ -53,6 +54,7 @@
     public static final int FOCUS_STATE = 8;
 
     private SparseLongArray mPropStartDelay;
+    private SparseLongArray mPropInitialPlayTime;
     private SparseLongArray mPropDuration;
     private SparseArray<Interpolator> mPropInterpolators;
     private Animator.AnimatorListener mListener;
@@ -116,10 +118,14 @@
      * Applies the specific start delay, duration and interpolator to the given {@param animator}
      * for the specified {@param propertyType}.
      */
-    public <T extends Animator> T apply(@PropType int propertyType, T animator) {
+    public <T extends ValueAnimator> T apply(@PropType int propertyType, T animator) {
         animator.setStartDelay(getStartDelay(propertyType));
         animator.setDuration(getDuration(propertyType));
         animator.setInterpolator(getInterpolator(propertyType));
+        long initialPlayTime = getInitialPlayTime(propertyType);
+        if (initialPlayTime != 0) {
+            animator.setCurrentPlayTime(initialPlayTime);
+        }
         return animator;
     }
 
@@ -135,6 +141,17 @@
     }
 
     /**
+     * Sets a initial play time for a specific property.
+     */
+    public AnimationProps setInitialPlayTime(@PropType int propertyType, int initialPlayTime) {
+        if (mPropInitialPlayTime == null) {
+            mPropInitialPlayTime = new SparseLongArray();
+        }
+        mPropInitialPlayTime.append(propertyType, initialPlayTime);
+        return this;
+    }
+
+    /**
      * Returns the start delay for a specific property.
      */
     public long getStartDelay(@PropType int propertyType) {
@@ -200,6 +217,20 @@
     }
 
     /**
+     * Returns the initial play time for a specific property, falling back to the general initial
+     * play time if there is no specific property interpolator.
+     */
+    public long getInitialPlayTime(@PropType int propertyType) {
+        if (mPropInitialPlayTime != null) {
+            if (mPropInitialPlayTime.indexOfKey(propertyType) != -1) {
+                return mPropInitialPlayTime.get(propertyType);
+            }
+            return mPropInitialPlayTime.get(ALL, 0);
+        }
+        return 0;
+    }
+
+    /**
      * Sets an animator listener for this animation.
      */
     public AnimationProps setListener(Animator.AnimatorListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
index 1238c63..e3c3af0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsTransitionHelper.java
@@ -51,6 +51,7 @@
 import com.android.systemui.recents.misc.SystemServicesProxy;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
+import com.android.systemui.statusbar.BaseStatusBar;
 
 import java.util.ArrayList;
 import java.util.Collections;
@@ -167,6 +168,8 @@
                         animStartedListener);
             }
         }
+        Recents.getSystemServices().sendCloseSystemWindows(
+                BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
     }
 
     public IRemoteCallback wrapStartedListener(final OnAnimationStartedListener listener) {
@@ -284,7 +287,6 @@
         }
 
         // Calculate the offscreen task rect (for tasks that are not backed by views)
-        float stackScroll = stackView.getScroller().getStackScroll();
         TaskView taskView = stackView.getChildViewForTask(task);
         TaskStackLayoutAlgorithm stackLayout = stackView.getStackAlgorithm();
         Rect offscreenTaskRect = new Rect();
@@ -404,7 +406,7 @@
         transform.rect.round(taskRect);
         if (stackView.getStack().getStackFrontMostTask(false /* includeFreeformTasks */) !=
                 taskView.getTask()) {
-            taskRect.bottom = 2 * Recents.getSystemServices().getDisplayRect().height();
+            taskRect.bottom = taskRect.top + stackView.getMeasuredHeight();
         }
         return new AppTransitionAnimationSpec(taskView.getTask().key.id, b, taskRect);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index 6ecd52d..fd27b4f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -88,7 +88,6 @@
 
     private static final String TAG = "RecentsView";
 
-    private static final int DOCK_AREA_OVERLAY_TRANSITION_DURATION = 135;
     private static final int DEFAULT_UPDATE_SCRIM_DURATION = 200;
     private static final float DEFAULT_SCRIM_ALPHA = 0.33f;
 
@@ -733,8 +732,8 @@
             TaskStack.DockState.ViewState viewState = dockState.viewState;
             if (newDockStates == null || !newDockStatesSet.contains(dockState)) {
                 // This is no longer visible, so hide it
-                viewState.startAnimation(null, 0, 0, DOCK_AREA_OVERLAY_TRANSITION_DURATION,
-                        Interpolators.ALPHA_OUT, animateAlpha, animateBounds);
+                viewState.startAnimation(null, 0, 0, TaskStackView.SLOW_SYNC_STACK_DURATION,
+                        Interpolators.FAST_OUT_SLOW_IN, animateAlpha, animateBounds);
             } else {
                 // This state is now visible, update the bounds and show it
                 int areaAlpha = overrideAreaAlpha != -1
@@ -752,7 +751,7 @@
                     viewState.dockAreaOverlay.setBounds(bounds);
                 }
                 viewState.startAnimation(bounds, areaAlpha, hintAlpha,
-                        DOCK_AREA_OVERLAY_TRANSITION_DURATION, Interpolators.ALPHA_IN,
+                        TaskStackView.SLOW_SYNC_STACK_DURATION, Interpolators.FAST_OUT_SLOW_IN,
                         animateAlpha, animateBounds);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 6115aa8..2ec180d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -202,8 +202,8 @@
      * Handles dragging touch events
      */
     private void handleTouchEvent(MotionEvent ev) {
-        int action = ev.getAction();
-        switch (action & MotionEvent.ACTION_MASK) {
+        int action = ev.getActionMasked();
+        switch (action) {
             case MotionEvent.ACTION_DOWN:
                 mDownPos.set((int) ev.getX(), (int) ev.getY());
                 break;
@@ -258,7 +258,7 @@
             case MotionEvent.ACTION_CANCEL: {
                 if (mDragRequested) {
                     EventBus.getDefault().send(new DragEndEvent(mDragTask, mTaskView,
-                            mLastDropTarget));
+                            action == MotionEvent.ACTION_UP ? mLastDropTarget : null));
                     break;
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
index 2f3019c..995f9f7 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -28,7 +28,6 @@
 import com.android.systemui.recents.events.activity.EnterRecentsWindowAnimationCompletedEvent;
 import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
 import com.android.systemui.recents.events.activity.MultiWindowStateChangedEvent;
-import com.android.systemui.recents.misc.SystemServicesProxy;
 
 /** Manages the scrims for the various system bars. */
 public class SystemBarScrimViews {
@@ -51,7 +50,7 @@
         mNavBarScrimView.forceHasOverlappingRendering(false);
         mNavBarScrimEnterDuration = activity.getResources().getInteger(
                 R.integer.recents_nav_bar_scrim_enter_duration);
-        mHasNavBarScrim = Recents.getSystemServices().hasTransposedNavBar();
+        mHasNavBarScrim = Recents.getSystemServices().hasTransposedNavigationBar();
         mHasDockedTasks = Recents.getSystemServices().hasDockedTask();
     }
 
@@ -145,7 +144,7 @@
 
     public final void onBusEvent(ConfigurationChangedEvent event) {
         if (event.fromDeviceOrientationChange) {
-            mHasNavBarScrim = Recents.getSystemServices().hasTransposedNavBar();
+            mHasNavBarScrim = Recents.getSystemServices().hasTransposedNavigationBar();
         }
         animateScrimToCurrentNavBarState(event.hasStackTasks);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
index e79306f..b422cca 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
+import android.animation.TimeInterpolator;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -32,7 +33,6 @@
 import com.android.systemui.recents.RecentsActivityLaunchState;
 import com.android.systemui.recents.RecentsConfiguration;
 import com.android.systemui.recents.misc.ReferenceCountedTrigger;
-import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.model.TaskStack;
 
@@ -74,32 +74,35 @@
         void onStartFrontTaskEnterAnimation(boolean screenPinningEnabled);
     }
 
+    private static final int DOUBLE_FRAME_OFFSET_MS = 33;
     private static final int FRAME_OFFSET_MS = 16;
 
-    public static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
-    public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 333;
+    private static final int ENTER_EXIT_NUM_ANIMATING_TASKS = 5;
 
-    private static final PathInterpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
-            new PathInterpolator(0, 0, 0, 1f);
-    private static final PathInterpolator ENTER_FROM_HOME_ALPHA_INTERPOLATOR =
-            new PathInterpolator(0, 0, 0.2f, 1f);
+    private static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
+    public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 300;
+    private static final Interpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
+            Interpolators.LINEAR_OUT_SLOW_IN;
+    private static final Interpolator ENTER_FROM_HOME_ALPHA_INTERPOLATOR = Interpolators.LINEAR;
 
-    public static final int EXIT_TO_HOME_ALPHA_DURATION = 100;
-    public static final int EXIT_TO_HOME_TRANSLATION_DURATION = 150;
-    private static final PathInterpolator EXIT_TO_HOME_TRANSLATION_INTERPOLATOR =
-            new PathInterpolator(0.8f, 0, 0.6f, 1f);
-    private static final PathInterpolator EXIT_TO_HOME_ALPHA_INTERPOLATOR =
+    public static final int EXIT_TO_HOME_TRANSLATION_DURATION = 200;
+    private static final Interpolator EXIT_TO_HOME_TRANSLATION_INTERPOLATOR =
+            new PathInterpolator(0.4f, 0, 0.6f, 1f);
+
+    private static final int DISMISS_TASK_DURATION = 175;
+    private static final int DISMISS_ALL_TASKS_DURATION = 200;
+    private static final Interpolator DISMISS_ALL_TRANSLATION_INTERPOLATOR =
             new PathInterpolator(0.4f, 0, 1f, 1f);
 
-    private static final PathInterpolator FOCUS_NEXT_TASK_INTERPOLATOR =
+    private static final Interpolator FOCUS_NEXT_TASK_INTERPOLATOR =
             new PathInterpolator(0.4f, 0, 0, 1f);
-    private static final PathInterpolator FOCUS_IN_FRONT_NEXT_TASK_INTERPOLATOR =
+    private static final Interpolator FOCUS_IN_FRONT_NEXT_TASK_INTERPOLATOR =
             new PathInterpolator(0, 0, 0, 1f);
-    private static final PathInterpolator FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR =
-            new PathInterpolator(0.4f, 0, 0.2f, 1f);
+    private static final Interpolator FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR =
+            Interpolators.LINEAR_OUT_SLOW_IN;
 
-    private static final PathInterpolator ENTER_WHILE_DOCKING_INTERPOLATOR =
-            new PathInterpolator(0, 0, 0.2f, 1f);
+    private static final Interpolator ENTER_WHILE_DOCKING_INTERPOLATOR =
+            Interpolators.LINEAR_OUT_SLOW_IN;
 
     private TaskStackView mStackView;
 
@@ -251,16 +254,20 @@
                 }
 
             } else if (launchState.launchedFromHome) {
-                // Animate the tasks up
+                // Animate the tasks up, but offset the animations to be relative to the front-most
+                // task animation
                 AnimationProps taskAnimation = new AnimationProps()
-                        .setStartDelay(AnimationProps.ALPHA, taskIndexFromFront * FRAME_OFFSET_MS)
+                        .setInitialPlayTime(AnimationProps.BOUNDS,
+                                Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
+                                        DOUBLE_FRAME_OFFSET_MS)
+                        .setStartDelay(AnimationProps.ALPHA,
+                                Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS, taskIndexFromFront) *
+                                        FRAME_OFFSET_MS)
+                        .setDuration(AnimationProps.BOUNDS, ENTER_FROM_HOME_TRANSLATION_DURATION)
                         .setDuration(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_DURATION)
-                        .setDuration(AnimationProps.BOUNDS, ENTER_FROM_HOME_TRANSLATION_DURATION -
-                                (taskIndexFromFront * FRAME_OFFSET_MS))
                         .setInterpolator(AnimationProps.BOUNDS,
                                 ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR)
-                        .setInterpolator(AnimationProps.ALPHA,
-                                ENTER_FROM_HOME_ALPHA_INTERPOLATOR)
+                        .setInterpolator(AnimationProps.ALPHA, ENTER_FROM_HOME_ALPHA_INTERPOLATOR)
                         .setListener(postAnimationTrigger.decrementOnAnimationEnd());
                 postAnimationTrigger.increment();
                 mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
@@ -270,8 +277,8 @@
             } else if (launchState.launchedViaDockGesture) {
                 // Animate the tasks up
                 AnimationProps taskAnimation = new AnimationProps()
-                        .setDuration(AnimationProps.BOUNDS, (int) (dockGestureAnimDuration +
-                                                        (taskIndexFromBack * 2f * FRAME_OFFSET_MS)))
+                        .setDuration(AnimationProps.BOUNDS, dockGestureAnimDuration +
+                                (taskIndexFromBack * DOUBLE_FRAME_OFFSET_MS))
                         .setInterpolator(AnimationProps.BOUNDS,
                                 ENTER_WHILE_DOCKING_INTERPOLATOR)
                         .setListener(postAnimationTrigger.decrementOnAnimationEnd());
@@ -302,20 +309,17 @@
         for (int i = 0; i < taskViewCount; i++) {
             int taskIndexFromFront = taskViewCount - i - 1;
             TaskView tv = taskViews.get(i);
-            Task task = tv.getTask();
 
             // Animate the tasks down
             AnimationProps taskAnimation;
             if (animated) {
+                int delay = Math.min(ENTER_EXIT_NUM_ANIMATING_TASKS , taskIndexFromFront) *
+                        DOUBLE_FRAME_OFFSET_MS;
                 taskAnimation = new AnimationProps()
-                        .setStartDelay(AnimationProps.ALPHA, i * FRAME_OFFSET_MS)
-                        .setDuration(AnimationProps.ALPHA, EXIT_TO_HOME_ALPHA_DURATION)
-                        .setDuration(AnimationProps.BOUNDS, EXIT_TO_HOME_TRANSLATION_DURATION +
-                                (taskIndexFromFront * FRAME_OFFSET_MS))
+                        .setStartDelay(AnimationProps.BOUNDS, delay)
+                        .setDuration(AnimationProps.BOUNDS, EXIT_TO_HOME_TRANSLATION_DURATION)
                         .setInterpolator(AnimationProps.BOUNDS,
                                 EXIT_TO_HOME_TRANSLATION_INTERPOLATOR)
-                        .setInterpolator(AnimationProps.ALPHA,
-                                EXIT_TO_HOME_ALPHA_INTERPOLATOR)
                         .setListener(postAnimationTrigger.decrementOnAnimationEnd());
                 postAnimationTrigger.increment();
             } else {
@@ -323,7 +327,6 @@
             }
 
             mTmpTransform.fillIn(tv);
-            mTmpTransform.alpha = 0f;
             mTmpTransform.rect.offset(0, offscreenYOffset);
             mStackView.updateTaskViewToTransform(tv, mTmpTransform, taskAnimation);
         }
@@ -384,8 +387,6 @@
         Resources res = mStackView.getResources();
         TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
 
-        int taskViewRemoveAnimDuration = res.getInteger(
-                R.integer.recents_animate_task_view_remove_duration);
         int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
 
         // Disabling clipping with the stack while the view is animating away, this will get
@@ -393,7 +394,7 @@
         deleteTaskView.setClipViewInStack(false);
 
         // Compose the new animation and transform and star the animation
-        AnimationProps taskAnimation = new AnimationProps(taskViewRemoveAnimDuration,
+        AnimationProps taskAnimation = new AnimationProps(DISMISS_TASK_DURATION,
                 Interpolators.ALPHA_OUT, new AnimatorListenerAdapter() {
             @Override
             public void onAnimationEnd(Animator animation) {
@@ -413,29 +414,23 @@
      */
     public void startDeleteAllTasksAnimation(final List<TaskView> taskViews,
                                              final ReferenceCountedTrigger postAnimationTrigger) {
-        Resources res = mStackView.getResources();
         TaskStackLayoutAlgorithm stackLayout = mStackView.getStackAlgorithm();
 
-        int taskViewRemoveAnimDuration = res.getInteger(
-                R.integer.recents_animate_task_views_remove_all_duration);
         int offscreenXOffset = mStackView.getMeasuredWidth() - stackLayout.mTaskRect.left;
 
         int taskViewCount = taskViews.size();
-        int startDelayMax = 125;
 
         for (int i = taskViewCount - 1; i >= 0; i--) {
             TaskView tv = taskViews.get(i);
-            int indexFromFront = taskViewCount - i - 1;
-            float x = Interpolators.ACCELERATE.getInterpolation((float) indexFromFront /
-                    taskViewCount);
-            int startDelay = (int) Utilities.mapRange(x, 0, startDelayMax);
+            int taskIndexFromFront = taskViewCount - i - 1;
+            int startDelay = taskIndexFromFront * DOUBLE_FRAME_OFFSET_MS;
 
             // Disabling clipping with the stack while the view is animating away
             tv.setClipViewInStack(false);
 
             // Compose the new animation and transform and star the animation
             AnimationProps taskAnimation = new AnimationProps(startDelay,
-                    taskViewRemoveAnimDuration, Interpolators.FAST_OUT_LINEAR_IN,
+                    DISMISS_ALL_TASKS_DURATION, DISMISS_ALL_TRANSLATION_INTERPOLATOR,
                     new AnimatorListenerAdapter() {
                 @Override
                 public void onAnimationEnd(Animator animation) {
@@ -605,7 +600,7 @@
                 // Now, animate in the front-most task
                 if (frontMostTaskView != null) {
                     mStackView.updateTaskViewToTransform(frontMostTaskView, frontMostTransform,
-                            new AnimationProps(75, 200, FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR));
+                            new AnimationProps(75, 250, FOCUS_BEHIND_NEXT_TASK_INTERPOLATOR));
                 }
             }
         });
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
index 0022d66..fc7bba5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -416,7 +416,7 @@
         int prevFocusState = mFocusState;
         mFocusState = focusState;
         updateFrontBackTransforms();
-        if (mCb != null) {
+        if (mCb != null && (prevFocusState != focusState)) {
             mCb.onFocusStateChanged(prevFocusState, focusState);
         }
     }
@@ -432,10 +432,9 @@
      * Computes the stack and task rects.  The given task stack bounds already has the top/right
      * insets and left/right padding already applied.
      */
-    public void initialize(Rect windowRect, Rect taskStackBounds, StackState state) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
+    public void initialize(Rect displayRect, Rect windowRect, Rect taskStackBounds,
+            StackState state) {
         Rect lastStackRect = new Rect(mStackRect);
-        Rect displayRect = ssp.getDisplayRect();
 
         int topMargin = getScaleForExtent(windowRect, displayRect, mBaseTopMargin, mMinMargin, HEIGHT);
         int bottomMargin = getScaleForExtent(windowRect, displayRect, mBaseBottomMargin, mMinMargin,
@@ -999,14 +998,12 @@
      * top and right system insets (but not the bottom inset) and left/right paddings, but _not_
      * the top/bottom padding or insets.
      */
-    public void getTaskStackBounds(Rect windowRect, int topInset, int rightInset,
+    public void getTaskStackBounds(Rect displayRect, Rect windowRect, int topInset, int rightInset,
             Rect taskStackBounds) {
         taskStackBounds.set(windowRect.left, windowRect.top + topInset,
                 windowRect.right - rightInset, windowRect.bottom);
 
         // Ensure that the new width is at most the smaller display edge size
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        Rect displayRect = ssp.getDisplayRect();
         int sideMargin = getScaleForExtent(windowRect, displayRect, mBaseSideMargin, mMinMargin,
                 WIDTH);
         int targetStackWidth = taskStackBounds.width() - 2 * sideMargin;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 610b4e1..6732b17 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -25,6 +25,7 @@
 import android.annotation.IntDef;
 import android.content.ComponentName;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
@@ -109,6 +110,7 @@
     private static final float HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
 
     public static final int DEFAULT_SYNC_STACK_DURATION = 200;
+    public static final int SLOW_SYNC_STACK_DURATION = 250;
     private static final int DRAG_SCALE_DURATION = 175;
     static final float DRAG_SCALE_FACTOR = 1.05f;
 
@@ -126,48 +128,48 @@
     /** Update only the layout to the initial state. */
     private static final int INITIAL_STATE_UPDATE_LAYOUT_ONLY = 2;
 
-    LayoutInflater mInflater;
-    TaskStack mStack = new TaskStack();
+    private LayoutInflater mInflater;
+    private TaskStack mStack = new TaskStack();
     @ViewDebug.ExportedProperty(deepExport=true, prefix="layout_")
     TaskStackLayoutAlgorithm mLayoutAlgorithm;
     // The stable layout algorithm is only used to calculate the task rect with the stable bounds
-    TaskStackLayoutAlgorithm mStableLayoutAlgorithm;
+    private TaskStackLayoutAlgorithm mStableLayoutAlgorithm;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="scroller_")
-    TaskStackViewScroller mStackScroller;
+    private TaskStackViewScroller mStackScroller;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="touch_")
-    TaskStackViewTouchHandler mTouchHandler;
-    TaskStackAnimationHelper mAnimationHelper;
-    GradientDrawable mFreeformWorkspaceBackground;
-    ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
-    ViewPool<TaskView, Task> mViewPool;
+    private TaskStackViewTouchHandler mTouchHandler;
+    private TaskStackAnimationHelper mAnimationHelper;
+    private GradientDrawable mFreeformWorkspaceBackground;
+    private ObjectAnimator mFreeformWorkspaceBackgroundAnimator;
+    private ViewPool<TaskView, Task> mViewPool;
 
-    ArrayList<TaskView> mTaskViews = new ArrayList<>();
-    ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
-    ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
-    AnimationProps mDeferredTaskViewLayoutAnimation = null;
+    private ArrayList<TaskView> mTaskViews = new ArrayList<>();
+    private ArrayList<TaskViewTransform> mCurrentTaskTransforms = new ArrayList<>();
+    private ArraySet<Task.TaskKey> mIgnoreTasks = new ArraySet<>();
+    private AnimationProps mDeferredTaskViewLayoutAnimation = null;
 
     @ViewDebug.ExportedProperty(deepExport=true, prefix="doze_")
-    DozeTrigger mUIDozeTrigger;
+    private DozeTrigger mUIDozeTrigger;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="focused_task_")
-    Task mFocusedTask;
+    private Task mFocusedTask;
 
-    int mTaskCornerRadiusPx;
+    private int mTaskCornerRadiusPx;
     private int mDividerSize;
     private int mStartTimerIndicatorDuration;
 
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mTaskViewsClipDirty = true;
+    private boolean mTaskViewsClipDirty = true;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mAwaitingFirstLayout = true;
+    private boolean mAwaitingFirstLayout = true;
     @ViewDebug.ExportedProperty(category="recents")
     @InitialStateAction
-    int mInitialState = INITIAL_STATE_UPDATE_ALL;
+    private int mInitialState = INITIAL_STATE_UPDATE_ALL;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mInMeasureLayout = false;
+    private boolean mInMeasureLayout = false;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mEnterAnimationComplete = false;
+    private boolean mEnterAnimationComplete = false;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mTouchExplorationEnabled;
+    private boolean mTouchExplorationEnabled;
     @ViewDebug.ExportedProperty(category="recents")
     boolean mScreenPinningEnabled;
 
@@ -183,12 +185,17 @@
     // The current window bounds are dynamic and may change as the user drags and drops
     @ViewDebug.ExportedProperty(category="recents")
     private Rect mWindowRect = new Rect();
+    // The current display bounds
+    @ViewDebug.ExportedProperty(category="recents")
+    private Rect mDisplayRect = new Rect();
+    // The current display orientation
+    @ViewDebug.ExportedProperty(category="recents")
+    private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
 
     private Rect mTmpRect = new Rect();
     private ArrayMap<Task.TaskKey, TaskView> mTmpTaskViewMap = new ArrayMap<>();
     private List<TaskView> mTmpTaskViews = new ArrayList<>();
     private TaskViewTransform mTmpTransform = new TaskViewTransform();
-    private ArrayList<TaskViewTransform> mTmpTaskTransforms = new ArrayList<>();
     private int[] mTmpIntPair = new int[2];
     private boolean mResetToInitialStateWhenResized;
     private int mLastWidth;
@@ -248,6 +255,8 @@
         mTaskCornerRadiusPx = res.getDimensionPixelSize(
                 R.dimen.recents_task_view_rounded_corners_radius);
         mDividerSize = ssp.getDockedDividerSize(context);
+        mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
+        mDisplayRect = ssp.getDisplayRect();
 
         int taskBarDismissDozeDelaySeconds = getResources().getInteger(
                 R.integer.recents_task_bar_dismiss_delay_seconds);
@@ -638,7 +647,7 @@
      */
     private void relayoutTaskViews(AnimationProps animation, boolean ignoreTaskOverrides) {
         // If we had a deferred animation, cancel that
-        mDeferredTaskViewLayoutAnimation = null;
+        cancelDeferredTaskViewLayoutAnimation();
 
         // Synchronize the current set of TaskViews
         bindVisibleTaskViews(mStackScroller.getStackScroll(),
@@ -730,23 +739,12 @@
 
     /**
      * Cancels all {@link TaskView} animations.
-     *
-     * @see #cancelAllTaskViewAnimations(ArraySet<Task.TaskKey>)
      */
     void cancelAllTaskViewAnimations() {
-        cancelAllTaskViewAnimations(mIgnoreTasks);
-    }
-
-    /**
-     * Cancels all {@link TaskView} animations.
-     *
-     * @param ignoreTasksSet The set of tasks to continue running their animations.
-     */
-    void cancelAllTaskViewAnimations(ArraySet<Task.TaskKey> ignoreTasksSet) {
         List<TaskView> taskViews = getTaskViews();
         for (int i = taskViews.size() - 1; i >= 0; i--) {
             final TaskView tv = taskViews.get(i);
-            if (!ignoreTasksSet.contains(tv.getTask().key)) {
+            if (!mIgnoreTasks.contains(tv.getTask().key)) {
                 tv.cancelTransformAnimation();
             }
         }
@@ -1150,7 +1148,7 @@
         // Update the stable stack bounds, but only update the current stack bounds if the stable
         // bounds have changed.  This is because we may get spurious measures while dragging where
         // our current stack bounds reflect the target drop region.
-        mLayoutAlgorithm.getTaskStackBounds(new Rect(0, 0, width, height),
+        mLayoutAlgorithm.getTaskStackBounds(mDisplayRect, new Rect(0, 0, width, height),
                 mLayoutAlgorithm.mSystemInsets.top, mLayoutAlgorithm.mSystemInsets.right, mTmpRect);
         if (!mTmpRect.equals(mStableStackBounds)) {
             mStableStackBounds.set(mTmpRect);
@@ -1160,9 +1158,9 @@
         }
 
         // Compute the rects in the stack algorithm
-        mStableLayoutAlgorithm.initialize(mStableWindowRect, mStableStackBounds,
+        mStableLayoutAlgorithm.initialize(mDisplayRect, mStableWindowRect, mStableStackBounds,
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
-        mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
+        mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
         updateLayoutAlgorithm(false /* boundScroll */);
 
@@ -1538,7 +1536,7 @@
 
     private void bindTaskView(TaskView tv, Task task) {
         // Rebind the task and request that this task's data be filled into the TaskView
-        tv.onTaskBound(task);
+        tv.onTaskBound(task, mTouchExplorationEnabled, mDisplayOrientation, mDisplayRect);
 
         // Load the task data
         Recents.getTaskLoader().loadTaskData(task);
@@ -1666,8 +1664,10 @@
 
     public final void onBusEvent(DismissRecentsToHomeAnimationStarted event) {
         // Stop any scrolling
+        cancelDeferredTaskViewLayoutAnimation();
         mStackScroller.stopScroller();
         mStackScroller.stopBoundScrollAnimation();
+        mTouchHandler.finishAnimations();
 
         // Start the task animations
         mAnimationHelper.startExitToHomeAnimation(event.animated, event.getAnimationTrigger());
@@ -1789,7 +1789,8 @@
     }
 
     public final void onBusEvent(DragDropTargetChangedEvent event) {
-        AnimationProps animation = new AnimationProps(250, Interpolators.FAST_OUT_SLOW_IN);
+        AnimationProps animation = new AnimationProps(SLOW_SYNC_STACK_DURATION,
+                Interpolators.FAST_OUT_SLOW_IN);
         boolean ignoreTaskOverrides = false;
         if (event.dropTarget instanceof TaskStack.DockState) {
             // Calculate the new task stack bounds that matches the window size that Recents will
@@ -1802,11 +1803,11 @@
             int height = getMeasuredHeight();
             height -= systemInsets.bottom;
             systemInsets.bottom = 0;
-            mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
+            mStackBounds.set(dockState.getDockedTaskStackBounds(mDisplayRect, getMeasuredWidth(),
                     height, mDividerSize, systemInsets,
                     mLayoutAlgorithm, getResources(), mWindowRect));
             mLayoutAlgorithm.setSystemInsets(systemInsets);
-            mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
+            mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
             updateLayoutAlgorithm(true /* boundScroll */);
             ignoreTaskOverrides = true;
@@ -1817,7 +1818,7 @@
             mStackBounds.set(mStableStackBounds);
             removeIgnoreTask(event.task);
             mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
-            mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
+            mLayoutAlgorithm.initialize(mDisplayRect, mWindowRect, mStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
             updateLayoutAlgorithm(true /* boundScroll */);
             addIgnoreTask(event.task);
@@ -1960,6 +1961,10 @@
     }
 
     public final void onBusEvent(ConfigurationChangedEvent event) {
+        if (event.fromDeviceOrientationChange) {
+            mDisplayOrientation = Utilities.getAppConfiguration(mContext).orientation;
+            mDisplayRect = Recents.getSystemServices().getDisplayRect();
+        }
         reloadOnConfigurationChange();
 
         // Notify the task views of the configuration change so they can reload their resources
@@ -2072,6 +2077,8 @@
         writer.print(" stackBounds="); writer.print(Utilities.dumpRect(mStackBounds));
         writer.print(" stableWindow="); writer.print(Utilities.dumpRect(mStableWindowRect));
         writer.print(" window="); writer.print(Utilities.dumpRect(mWindowRect));
+        writer.print(" display="); writer.print(Utilities.dumpRect(mDisplayRect));
+        writer.print(" orientation="); writer.print(mDisplayOrientation);
         writer.print(" [0x"); writer.print(id); writer.print("]");
         writer.println();
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
index 9edf9d6..81242fd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java
@@ -188,6 +188,18 @@
         return true;
     }
 
+    /**
+     * Finishes all scroll-fling and swipe animations currently running.
+     */
+    public void finishAnimations() {
+        Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
+        ArrayMap<View, Animator> existingAnimators = new ArrayMap<>(mSwipeHelperAnimations);
+        for (int i = 0; i < existingAnimators.size(); i++) {
+            existingAnimators.get(existingAnimators.keyAt(i)).end();
+        }
+        mSwipeHelperAnimations.clear();
+    }
+
     private boolean handleTouchEvent(MotionEvent ev) {
         // Short circuit if we have no children
         if (mSv.getTaskViews().size() == 0) {
@@ -207,19 +219,11 @@
                 mActiveTaskView = findViewAtPoint(mDownX, mDownY);
 
                 // Stop the current scroll if it is still flinging
+                mSv.cancelDeferredTaskViewLayoutAnimation();
                 mScroller.stopScroller();
                 mScroller.stopBoundScrollAnimation();
                 mScroller.resetDeltaScroll();
-                Utilities.cancelAnimationWithoutCallbacks(mScrollFlingAnimator);
-
-                // Finish any existing task animations from the delete
-                mSv.cancelAllTaskViewAnimations();
-                // Finish any of the swipe helper animations
-                ArrayMap<View, Animator> existingAnimators = new ArrayMap<>(mSwipeHelperAnimations);
-                for (int i = 0; i < existingAnimators.size(); i++) {
-                    existingAnimators.get(existingAnimators.keyAt(i)).end();
-                }
-                mSwipeHelperAnimations.clear();
+                finishAnimations();
 
                 // Initialize the velocity tracker
                 initOrResetVelocityTracker();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
index 7ea70b5..1d476c6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -126,21 +126,21 @@
             };
 
     @ViewDebug.ExportedProperty(category="recents")
-    float mDimAlpha;
-    float mActionButtonTranslationZ;
+    private float mDimAlpha;
+    private float mActionButtonTranslationZ;
 
     @ViewDebug.ExportedProperty(deepExport=true, prefix="task_")
-    Task mTask;
+    private Task mTask;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mTaskDataLoaded;
+    private boolean mTaskDataLoaded;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mClipViewInStack = true;
+    private boolean mClipViewInStack = true;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mTouchExplorationEnabled;
+    private boolean mTouchExplorationEnabled;
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mIsDisabledInSafeMode;
+    private boolean mIsDisabledInSafeMode;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="view_bounds_")
-    AnimateableViewBounds mViewBounds;
+    private AnimateableViewBounds mViewBounds;
 
     private AnimatorSet mTransformAnimation;
     private ObjectAnimator mDimAnimator;
@@ -152,12 +152,12 @@
     TaskViewThumbnail mThumbnailView;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
     TaskViewHeader mHeaderView;
-    View mActionButtonView;
-    View mIncompatibleAppToastView;
-    TaskViewCallbacks mCb;
+    private View mActionButtonView;
+    private View mIncompatibleAppToastView;
+    private TaskViewCallbacks mCb;
 
     @ViewDebug.ExportedProperty(category="recents")
-    Point mDownTouchPos = new Point();
+    private Point mDownTouchPos = new Point();
 
     private Toast mDisabledAppToast;
 
@@ -196,7 +196,6 @@
      */
     void onReload(boolean isResumingFromVisible) {
         resetNoUserInteractionState();
-        readSystemFlags();
         if (!isResumingFromVisible) {
             resetViewProperties();
         }
@@ -213,12 +212,6 @@
     }
 
     @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        readSystemFlags();
-    }
-
-    @Override
     protected void onFinishInflate() {
         // Bind the views
         mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
@@ -598,12 +591,14 @@
 
     /**** TaskCallbacks Implementation ****/
 
-    public void onTaskBound(Task t) {
+    public void onTaskBound(Task t, boolean touchExplorationEnabled, int displayOrientation,
+            Rect displayRect) {
         SystemServicesProxy ssp = Recents.getSystemServices();
+        mTouchExplorationEnabled = touchExplorationEnabled;
         mTask = t;
         mTask.addCallback(this);
         mIsDisabledInSafeMode = !mTask.isSystemApp && ssp.isInSafeMode();
-        mThumbnailView.bindToTask(mTask, mIsDisabledInSafeMode);
+        mThumbnailView.bindToTask(mTask, mIsDisabledInSafeMode, displayOrientation, displayRect);
         mHeaderView.bindToTask(mTask, mTouchExplorationEnabled, mIsDisabledInSafeMode);
 
         if (!t.isDockable && ssp.hasDockedTask()) {
@@ -709,12 +704,4 @@
         }
         EventBus.getDefault().unregister(this);
     }
-
-    /**
-     * Reads current system flags related to accessibility and screen pinning.
-     */
-    private void readSystemFlags() {
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
index 109dc20..3193759 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -29,16 +29,12 @@
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.graphics.Shader;
 import android.util.AttributeSet;
 import android.view.View;
 import android.view.ViewDebug;
 
 import com.android.systemui.R;
-import com.android.systemui.recents.Recents;
-import com.android.systemui.recents.misc.SystemServicesProxy;
-import com.android.systemui.recents.misc.Utilities;
 import com.android.systemui.recents.model.Task;
 
 
@@ -53,41 +49,38 @@
 
     private Task mTask;
 
+    private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
     private Rect mDisplayRect = new Rect();
-    private int mOrientation = Configuration.ORIENTATION_UNDEFINED;
 
     // Drawing
     @ViewDebug.ExportedProperty(category="recents")
-    Rect mTaskViewRect = new Rect();
+    private Rect mTaskViewRect = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    Rect mThumbnailRect = new Rect();
+    private Rect mThumbnailRect = new Rect();
     @ViewDebug.ExportedProperty(category="recents")
-    float mThumbnailScale;
-    float mFullscreenThumbnailScale;
-    ActivityManager.TaskThumbnailInfo mThumbnailInfo;
+    private float mThumbnailScale;
+    private float mFullscreenThumbnailScale;
+    private ActivityManager.TaskThumbnailInfo mThumbnailInfo;
 
-    int mCornerRadius;
+    private int mCornerRadius;
     @ViewDebug.ExportedProperty(category="recents")
-    float mDimAlpha;
-    Matrix mScaleMatrix = new Matrix();
-    Paint mDrawPaint = new Paint();
-    Paint mBgFillPaint = new Paint();
-    BitmapShader mBitmapShader;
-    LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
+    private float mDimAlpha;
+    private Matrix mScaleMatrix = new Matrix();
+    private Paint mDrawPaint = new Paint();
+    private Paint mBgFillPaint = new Paint();
+    private BitmapShader mBitmapShader;
+    private LightingColorFilter mLightingColorFilter = new LightingColorFilter(0xffffffff, 0);
 
-    // Task bar clipping, the top of this thumbnail can be clipped against the opaque header
-    // bar that overlaps this thumbnail
-    View mTaskBar;
-    @ViewDebug.ExportedProperty(category="recents")
-    Rect mClipRect = new Rect();
+    // Clip the top of the thumbnail against the opaque header bar that overlaps this view
+    private View mTaskBar;
 
     // Visibility optimization, if the thumbnail height is less than the height of the header
     // bar for the task view, then just mark this thumbnail view as invisible
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mInvisible;
+    private boolean mInvisible;
 
     @ViewDebug.ExportedProperty(category="recents")
-    boolean mDisabledInSafeMode;
+    private boolean mDisabledInSafeMode;
 
     public TaskViewThumbnail(Context context) {
         this(context, null);
@@ -129,15 +122,6 @@
     }
 
     @Override
-    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
-        SystemServicesProxy ssp = Recents.getSystemServices();
-        mOrientation = Utilities.getAppConfiguration(mContext).orientation;
-        mDisplayRect = ssp.getDisplayRect();
-    }
-
-    @Override
     protected void onDraw(Canvas canvas) {
         if (mInvisible) {
             return;
@@ -247,7 +231,7 @@
                 mThumbnailScale = 0f;
             } else if (isStackTask) {
                 float invThumbnailScale = 1f / mFullscreenThumbnailScale;
-                if (mOrientation == Configuration.ORIENTATION_PORTRAIT) {
+                if (mDisplayOrientation == Configuration.ORIENTATION_PORTRAIT) {
                     if (mThumbnailInfo.screenOrientation == Configuration.ORIENTATION_PORTRAIT) {
                         // If we are in the same orientation as the screenshot, just scale it to the
                         // width of the task view
@@ -306,9 +290,11 @@
     /**
      * Binds the thumbnail view to the task.
      */
-    void bindToTask(Task t, boolean disabledInSafeMode) {
+    void bindToTask(Task t, boolean disabledInSafeMode, int displayOrientation, Rect displayRect) {
         mTask = t;
         mDisabledInSafeMode = disabledInSafeMode;
+        mDisplayOrientation = displayOrientation;
+        mDisplayRect.set(displayRect);
         if (t.colorBackground != 0) {
             mBgFillPaint.setColor(t.colorBackground);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 44a167b..7379706 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -32,7 +32,6 @@
 import android.hardware.display.DisplayManager;
 import android.os.Bundle;
 import android.util.AttributeSet;
-import android.util.MutableInt;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.GestureDetector;
@@ -105,6 +104,8 @@
             new PathInterpolator(0.5f, 1f, 0.5f, 1f);
     private static final PathInterpolator DIM_INTERPOLATOR =
             new PathInterpolator(.23f, .87f, .52f, -0.11f);
+    private static final Interpolator IME_ADJUST_INTERPOLATOR =
+            new PathInterpolator(0.2f, 0f, 0.1f, 1f);
 
     private DividerHandleView mHandle;
     private View mBackground;
@@ -276,7 +277,7 @@
                     updateDockSide();
                     SystemServicesProxy ssp = Recents.getSystemServices();
                     if (mDockSide != WindowManager.DOCKED_INVALID
-                            && !ssp.isRecentsTopMost(ssp.getTopMostTask(), null /* isTopHome */)) {
+                            && !ssp.isRecentsActivityVisible()) {
                         mWindowManagerProxy.swapTasks();
                         return true;
                     }
@@ -701,7 +702,7 @@
             resetBackground();
         } else if (mDockSide == WindowManager.DOCKED_TOP) {
             mBackground.setPivotY(0);
-            mBackground.setScaleY(MINIMIZE_DOCK_SCALE);
+            mBackground.setScaleY(ADJUSTED_FOR_IME_SCALE);
         }
         mAdjustedForIme = adjustedForIme;
     }
@@ -709,20 +710,20 @@
     public void setAdjustedForIme(boolean adjustedForIme, long animDuration) {
         updateDockSide();
         mHandle.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setInterpolator(IME_ADJUST_INTERPOLATOR)
                 .setDuration(animDuration)
                 .alpha(adjustedForIme ? 0f : 1f)
                 .start();
         if (mDockSide == WindowManager.DOCKED_TOP) {
             mBackground.setPivotY(0);
             mBackground.animate()
-                    .scaleY(adjustedForIme ? MINIMIZE_DOCK_SCALE : 1f);
+                    .scaleY(adjustedForIme ? ADJUSTED_FOR_IME_SCALE : 1f);
         }
         if (!adjustedForIme) {
             mBackground.animate().withEndAction(mResetBackgroundRunnable);
         }
         mBackground.animate()
-                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .setInterpolator(IME_ADJUST_INTERPOLATOR)
                 .setDuration(animDuration)
                 .start();
         mAdjustedForIme = adjustedForIme;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 2d5b6d4..ef6d73a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -143,6 +143,7 @@
     protected static final int MSG_SHOW_NEXT_AFFILIATED_TASK = 1024;
     protected static final int MSG_SHOW_PREV_AFFILIATED_TASK = 1025;
     protected static final int MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU = 1026;
+    protected static final int MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU = 1027;
 
     protected static final boolean ENABLE_HEADS_UP = true;
     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
@@ -537,8 +538,7 @@
                     );
                 }
             } else if (WORK_CHALLENGE_UNLOCKED_NOTIFICATION_ACTION.equals(action)) {
-                final IntentSender intentSender = (IntentSender) intent
-                        .getParcelableExtra(Intent.EXTRA_INTENT);
+                final IntentSender intentSender = intent.getParcelableExtra(Intent.EXTRA_INTENT);
                 final String notificationKey = intent.getStringExtra(Intent.EXTRA_INDEX);
                 try {
                     mContext.startIntentSender(intentSender, null, 0, 0, 0);
@@ -1248,6 +1248,13 @@
     }
 
     @Override
+    public void dismissKeyboardShortcutsMenu() {
+        int msg = MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU;
+        mHandler.removeMessages(msg);
+        mHandler.sendEmptyMessage(msg);
+    }
+
+    @Override
     public void toggleKeyboardShortcutsMenu(int deviceId) {
         int msg = MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU;
         mHandler.removeMessages(msg);
@@ -1344,6 +1351,10 @@
         KeyboardShortcuts.toggle(mContext, deviceId);
     }
 
+    protected void dismissKeyboardShortcuts() {
+        KeyboardShortcuts.dismiss();
+    }
+
     protected void cancelPreloadingRecents() {
         if (mRecents != null) {
             mRecents.cancelPreloadingRecents();
@@ -1518,6 +1529,9 @@
              case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
                   toggleKeyboardShortcuts(m.arg1);
                   break;
+             case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
+                  dismissKeyboardShortcuts();
+                  break;
             }
         }
     }
@@ -1924,11 +1938,23 @@
             callBackIntent.putExtra(Intent.EXTRA_INDEX, notificationKey);
             callBackIntent.setPackage(mContext.getPackageName());
 
-            newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
-                    | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-            newIntent.putExtra(Intent.EXTRA_INTENT, PendingIntent
-                    .getBroadcast(mContext, 0, callBackIntent, 0).getIntentSender());
-            mContext.startActivity(newIntent);
+            PendingIntent callBackPendingIntent = PendingIntent.getBroadcast(
+                    mContext,
+                    0,
+                    callBackIntent,
+                    PendingIntent.FLAG_CANCEL_CURRENT |
+                            PendingIntent.FLAG_ONE_SHOT |
+                            PendingIntent.FLAG_IMMUTABLE
+            );
+            newIntent.putExtra(
+                    Intent.EXTRA_INTENT,
+                    callBackPendingIntent.getIntentSender()
+            );
+            try {
+                ActivityManagerNative.getDefault().startConfirmDeviceCredentialIntent(newIntent);
+            } catch (RemoteException ex) {
+                // ignore
+            }
             return true;
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
index f7d13ee..1bc2ebc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/CommandQueue.java
@@ -74,6 +74,7 @@
     private static final int MSG_CLICK_QS_TILE                 = 29 << MSG_SHIFT;
     private static final int MSG_TOGGLE_APP_SPLIT_SCREEN       = 30 << MSG_SHIFT;
     private static final int MSG_APP_TRANSITION_FINISHED       = 31 << MSG_SHIFT;
+    private static final int MSG_DISMISS_KEYBOARD_SHORTCUTS    = 32 << MSG_SHIFT;
 
     public static final int FLAG_EXCLUDE_NONE = 0;
     public static final int FLAG_EXCLUDE_SEARCH_PANEL = 1 << 0;
@@ -108,6 +109,7 @@
         void toggleRecentApps();
         void toggleSplitScreen();
         void preloadRecentApps();
+        void dismissKeyboardShortcutsMenu();
         void toggleKeyboardShortcutsMenu(int deviceId);
         void cancelPreloadRecentApps();
         void setWindowState(int window, int state);
@@ -256,6 +258,14 @@
     }
 
     @Override
+    public void dismissKeyboardShortcutsMenu() {
+        synchronized (mLock) {
+            mHandler.removeMessages(MSG_DISMISS_KEYBOARD_SHORTCUTS);
+            mHandler.obtainMessage(MSG_DISMISS_KEYBOARD_SHORTCUTS).sendToTarget();
+        }
+    }
+
+    @Override
     public void toggleKeyboardShortcutsMenu(int deviceId) {
         synchronized (mLock) {
             mHandler.removeMessages(MSG_TOGGLE_KEYBOARD_SHORTCUTS);
@@ -435,6 +445,9 @@
                 case MSG_CANCEL_PRELOAD_RECENT_APPS:
                     mCallbacks.cancelPreloadRecentApps();
                     break;
+                case MSG_DISMISS_KEYBOARD_SHORTCUTS:
+                    mCallbacks.dismissKeyboardShortcutsMenu();
+                    break;
                 case MSG_TOGGLE_KEYBOARD_SHORTCUTS:
                     mCallbacks.toggleKeyboardShortcutsMenu(msg.arg1);
                     break;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index 6e9de23..2806729 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -1346,7 +1346,7 @@
             expandButton.setVisibility(VISIBLE);
             mNotificationHeader.setOnClickListener(mExpandClickListener);
             mNotificationHeaderWrapper = NotificationViewWrapper.wrap(getContext(),
-                    mNotificationHeader);
+                    mNotificationHeader, this);
             addView(mNotificationHeader, indexOfChild(mChildrenContainer) + 1);
             mTranslateableViews.add(mNotificationHeader);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 5f4ebd8..8a5bece 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -27,6 +27,8 @@
     public void onReceive(Context context, Intent intent) {
         if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
             KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
+        } else if (Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
+            KeyboardShortcuts.dismiss();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 491ffde..7be50c4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -177,6 +177,13 @@
             if (updateContractedHeaderWidth()) {
                 mContractedChild.measure(widthMeasureSpec, heightSpec);
             }
+            if (mExpandedChild != null
+                    && mContractedChild.getMeasuredHeight() > mExpandedChild.getMeasuredHeight()) {
+                // the Expanded child is smaller then the collapsed. Let's remeasure it.
+                heightSpec = MeasureSpec.makeMeasureSpec(mContractedChild.getMeasuredHeight(),
+                        MeasureSpec.EXACTLY);
+                mExpandedChild.measure(widthMeasureSpec, heightSpec);
+            }
         }
         if (mHeadsUpChild != null) {
             int size = Math.min(maxSize, mHeadsUpHeight);
@@ -307,7 +314,8 @@
         addView(child);
         mContractedChild = child;
         mContractedChild.addOnLayoutChangeListener(mLayoutUpdater);
-        mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child);
+        mContractedWrapper = NotificationViewWrapper.wrap(getContext(), child,
+                mContainingNotification);
         selectLayout(false /* animate */, true /* force */);
         mContractedWrapper.setDark(mDark, false /* animate */, 0 /* delay */);
     }
@@ -321,7 +329,8 @@
         addView(child);
         mExpandedChild = child;
         mExpandedChild.addOnLayoutChangeListener(mLayoutUpdater);
-        mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child);
+        mExpandedWrapper = NotificationViewWrapper.wrap(getContext(), child,
+                mContainingNotification);
         selectLayout(false /* animate */, true /* force */);
     }
 
@@ -334,7 +343,8 @@
         addView(child);
         mHeadsUpChild = child;
         mHeadsUpChild.addOnLayoutChangeListener(mLayoutUpdater);
-        mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child);
+        mHeadsUpWrapper = NotificationViewWrapper.wrap(getContext(), child,
+                mContainingNotification);
         selectLayout(false /* animate */, true /* force */);
     }
 
@@ -834,10 +844,14 @@
     public void updateExpandButtons(boolean expandable) {
         mExpandable = expandable;
         // if the expanded child has the same height as the collapsed one we hide it.
-        if (mExpandedChild != null && mExpandedChild.getHeight() != 0 &&
-                ((mIsHeadsUp && mExpandedChild.getHeight() == mHeadsUpChild.getHeight()) ||
-                (!mIsHeadsUp && mExpandedChild.getHeight() == mContractedChild.getHeight()))) {
-            expandable = false;
+        if (mExpandedChild != null && mExpandedChild.getHeight() != 0) {
+            if ((!mIsHeadsUp || mHeadsUpChild == null)) {
+                if (mExpandedChild.getHeight() == mContractedChild.getHeight()) {
+                    expandable = false;
+                }
+            } else if (mExpandedChild.getHeight() == mHeadsUpChild.getHeight()) {
+                expandable = false;
+            }
         }
         if (mExpandedChild != null) {
             mExpandedWrapper.updateExpandability(expandable, mExpandClickListener);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
index 06d79a7..3363993 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationHeaderUtil.java
@@ -65,12 +65,7 @@
             ImageView expand = (ImageView) view.findViewById(
                     com.android.internal.R.id.expand_button);
             applyToChild(icon, apply, header.getOriginalIconColor());
-            int color = header.getOriginalNotificationColor();
-            if (color == Notification.COLOR_DEFAULT) {
-                color = view.getContext().getColor(
-                        com.android.internal.R.color.notification_icon_default_color);
-            }
-            applyToChild(expand, apply, color);
+            applyToChild(expand, apply, header.getOriginalNotificationColor());
         }
 
         private void applyToChild(View view, boolean shouldApply, int originalColor) {
@@ -116,7 +111,7 @@
                     @Override
                     public boolean compare(View parent, View child, Object parentData,
                             Object childData) {
-                        return parent.getVisibility() == View.VISIBLE;
+                        return parent.getVisibility() != View.GONE;
                     }
 
                     @Override
@@ -161,11 +156,11 @@
                 mComparators.get(compI).apply(row);
             }
             // We need to sanitize the dividers since they might be off-balance now
-            sanitizeDividers(row);
+            sanitizeHeaderViews(row);
         }
     }
 
-    private void sanitizeDividers(ExpandableNotificationRow row) {
+    private void sanitizeHeaderViews(ExpandableNotificationRow row) {
         if (row.isSummaryWithChildren()) {
             sanitizeHeader(row.getNotificationHeader());
             return;
@@ -188,9 +183,26 @@
         if (rowHeader == null) {
             return;
         }
+        final int childCount = rowHeader.getChildCount();
+        View time = rowHeader.findViewById(com.android.internal.R.id.time);
+        boolean hasVisibleText = false;
+        for (int i = 1; i < childCount - 1 ; i++) {
+            View child = rowHeader.getChildAt(i);
+            if (child instanceof TextView
+                    && child.getVisibility() != View.GONE
+                    && !mDividers.contains(Integer.valueOf(child.getId()))
+                    && child != time) {
+                hasVisibleText = true;
+                break;
+            }
+        }
+        // in case no view is visible we make sure the time is visible
+        int timeVisibility = !hasVisibleText
+                || mRow.getStatusBarNotification().getNotification().showsTimeOrChronometer()
+                ? View.VISIBLE : View.GONE;
+        time.setVisibility(timeVisibility);
         View left = null;
         View right;
-        final int childCount = rowHeader.getChildCount();
         for (int i = 1; i < childCount - 1 ; i++) {
             View child = rowHeader.getChildAt(i);
             if (mDividers.contains(Integer.valueOf(child.getId()))) {
@@ -202,14 +214,14 @@
                         // A divider was found, this needs to be hidden
                         i--;
                         break;
-                    } else if (right.getVisibility() == View.VISIBLE) {
+                    } else if (right.getVisibility() != View.GONE && right instanceof TextView) {
                         visible = left != null;
                         left = right;
                         break;
                     }
                 }
                 child.setVisibility(visible ? View.VISIBLE : View.GONE);
-            } else if (child.getVisibility() == View.VISIBLE) {
+            } else if (child.getVisibility() != View.GONE && child instanceof TextView) {
                 left = child;
             }
         }
@@ -219,7 +231,7 @@
         for (int compI = 0; compI < mComparators.size(); compI++) {
             mComparators.get(compI).apply(row, true /* reset */);
         }
-        sanitizeDividers(row);
+        sanitizeHeaderViews(row);
     }
 
     private static class HeaderProcessor {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
index 988d537..2b59c68 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/SignalClusterView.java
@@ -295,6 +295,14 @@
             return;
         }
         // Clear out all old subIds.
+        for (PhoneState state : mPhoneStates) {
+            if (state.mMobile != null) {
+                state.maybeStopAnimatableDrawable(state.mMobile);
+            }
+            if (state.mMobileDark != null) {
+                state.maybeStopAnimatableDrawable(state.mMobileDark);
+            }
+        }
         mPhoneStates.clear();
         if (mMobileSignalGroup != null) {
             mMobileSignalGroup.removeAllViews();
@@ -391,6 +399,11 @@
                 state.mMobile.setImageDrawable(null);
                 state.mLastMobileStrengthId = -1;
             }
+            if (state.mMobileDark != null) {
+                state.maybeStopAnimatableDrawable(state.mMobileDark);
+                state.mMobileDark.setImageDrawable(null);
+                state.mLastMobileStrengthId = -1;
+            }
             if (state.mMobileType != null) {
                 state.mMobileType.setImageDrawable(null);
                 state.mLastMobileTypeId = -1;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
index 811687c..d1fc780 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/CarStatusBar.java
@@ -178,7 +178,7 @@
         @Override
         public void onTaskStackChanged() {
             SystemServicesProxy ssp = Recents.getSystemServices();
-            ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getTopMostTask();
+            ActivityManager.RunningTaskInfo runningTaskInfo = ssp.getRunningTask();
             mController.taskChanged(runningTaskInfo.baseActivity.getPackageName());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
index c561601..6084770 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigPictureTemplateViewWrapper.java
@@ -23,13 +23,16 @@
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 
+import com.android.systemui.statusbar.ExpandableNotificationRow;
+
 /**
  * Wraps a notification containing a big picture template
  */
 public class NotificationBigPictureTemplateViewWrapper extends NotificationTemplateViewWrapper {
 
-    protected NotificationBigPictureTemplateViewWrapper(Context ctx, View view) {
-        super(ctx, view);
+    protected NotificationBigPictureTemplateViewWrapper(Context ctx, View view,
+            ExpandableNotificationRow row) {
+        super(ctx, view, row);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
index 487a7a0..3f49125 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationBigTextTemplateViewWrapper.java
@@ -21,6 +21,7 @@
 import android.view.View;
 
 import com.android.internal.widget.ImageFloatingTextView;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
 
 /**
@@ -30,8 +31,9 @@
 
     private ImageFloatingTextView mBigtext;
 
-    protected NotificationBigTextTemplateViewWrapper(Context ctx, View view) {
-        super(ctx, view);
+    protected NotificationBigTextTemplateViewWrapper(Context ctx, View view,
+            ExpandableNotificationRow row) {
+        super(ctx, view, row);
     }
 
     private void resolveViews(StatusBarNotification notification) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
index 49e4ba8..61df44a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationCustomViewWrapper.java
@@ -30,6 +30,7 @@
 
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
 /**
@@ -44,8 +45,8 @@
     private boolean mShouldInvertDark;
     private boolean mShowingLegacyBackground;
 
-    protected NotificationCustomViewWrapper(View view) {
-        super(view);
+    protected NotificationCustomViewWrapper(View view, ExpandableNotificationRow row) {
+        super(view, row);
         mInvertHelper = new ViewInvertHelper(view, NotificationPanelView.DOZE_ANIMATION_DURATION);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
index b201d8f..1bfbaa2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationHeaderViewWrapper.java
@@ -36,6 +36,7 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.ViewInvertHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.ViewTransformationHelper;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
@@ -61,8 +62,8 @@
     private ImageView mExpandButton;
     private NotificationHeaderView mNotificationHeader;
 
-    protected NotificationHeaderViewWrapper(Context ctx, View view) {
-        super(view);
+    protected NotificationHeaderViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
+        super(view, row);
         mIconDarkAlpha = ctx.getResources().getInteger(R.integer.doze_small_icon_alpha);
         mInvertHelper = new ViewInvertHelper(ctx, NotificationPanelView.DOZE_ANIMATION_DURATION);
         mTransformationHelper = new ViewTransformationHelper();
@@ -156,7 +157,9 @@
         } else {
             mInvertHelper.update(dark);
         }
-        if (mIcon != null) {
+        if (mIcon != null && !mRow.isChildInGroup()) {
+            // We don't update the color for children views / their icon is invisible anyway.
+            // It also may lead to bugs where the icon isn't correctly greyed out.
             boolean hadColorFilter = mNotificationHeader.getOriginalIconColor()
                     != NotificationHeaderView.NO_COLOR;
             if (fade) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
index 30698e1..3c95a78 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationMediaTemplateViewWrapper.java
@@ -20,6 +20,7 @@
 import android.service.notification.StatusBarNotification;
 import android.view.View;
 
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
 
 /**
@@ -27,8 +28,9 @@
  */
 public class NotificationMediaTemplateViewWrapper extends NotificationTemplateViewWrapper {
 
-    protected NotificationMediaTemplateViewWrapper(Context ctx, View view) {
-        super(ctx, view);
+    protected NotificationMediaTemplateViewWrapper(Context ctx, View view,
+            ExpandableNotificationRow row) {
+        super(ctx, view, row);
     }
 
     View mActions;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 78e23fc..889bd5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -25,11 +25,10 @@
 import android.widget.ProgressBar;
 import android.widget.TextView;
 
-import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.CrossFadeHelper;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.ViewTransformationHelper;
-import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 /**
  * Wraps a notification view inflated from a template.
@@ -43,8 +42,8 @@
     private TextView mTitle;
     private TextView mText;
 
-    protected NotificationTemplateViewWrapper(Context ctx, View view) {
-        super(ctx, view);
+    protected NotificationTemplateViewWrapper(Context ctx, View view, ExpandableNotificationRow row) {
+        super(ctx, view, row);
         mTransformationHelper.setCustomTransformation(
                 new ViewTransformationHelper.CustomTransformation() {
                     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
index ebff69d..7a0df1f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationViewWrapper.java
@@ -26,7 +26,7 @@
 
 import com.android.systemui.Interpolators;
 import com.android.systemui.statusbar.CrossFadeHelper;
-import com.android.systemui.statusbar.NotificationContentView;
+import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.TransformableView;
 import com.android.systemui.statusbar.phone.NotificationPanelView;
 
@@ -38,28 +38,30 @@
 
     protected final ColorMatrix mGrayscaleColorMatrix = new ColorMatrix();
     protected final View mView;
+    protected final ExpandableNotificationRow mRow;
     protected boolean mDark;
     protected boolean mDarkInitialized = false;
 
-    public static NotificationViewWrapper wrap(Context ctx, View v) {
+    public static NotificationViewWrapper wrap(Context ctx, View v, ExpandableNotificationRow row) {
         if (v.getId() == com.android.internal.R.id.status_bar_latest_event_content) {
             if ("bigPicture".equals(v.getTag())) {
-                return new NotificationBigPictureTemplateViewWrapper(ctx, v);
+                return new NotificationBigPictureTemplateViewWrapper(ctx, v, row);
             } else if ("bigText".equals(v.getTag())) {
-                return new NotificationBigTextTemplateViewWrapper(ctx, v);
+                return new NotificationBigTextTemplateViewWrapper(ctx, v, row);
             } else if ("media".equals(v.getTag()) || "bigMediaNarrow".equals(v.getTag())) {
-                return new NotificationMediaTemplateViewWrapper(ctx, v);
+                return new NotificationMediaTemplateViewWrapper(ctx, v, row);
             }
-            return new NotificationTemplateViewWrapper(ctx, v);
+            return new NotificationTemplateViewWrapper(ctx, v, row);
         } else if (v instanceof NotificationHeaderView) {
-            return new NotificationHeaderViewWrapper(ctx, v);
+            return new NotificationHeaderViewWrapper(ctx, v, row);
         } else {
-            return new NotificationCustomViewWrapper(v);
+            return new NotificationCustomViewWrapper(v, row);
         }
     }
 
-    protected NotificationViewWrapper(View view) {
+    protected NotificationViewWrapper(View view, ExpandableNotificationRow row) {
         mView = view;
+        mRow = row;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
index 48cf631..8617104 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationPanelView.java
@@ -41,9 +41,9 @@
 import android.widget.TextView;
 import com.android.internal.logging.MetricsLogger;
 import com.android.keyguard.KeyguardStatusView;
+import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.AutoReinflateContainer.InflateListener;
 import com.android.systemui.DejankUtils;
-import com.android.systemui.DensityContainer;
-import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -92,7 +92,7 @@
     private KeyguardUserSwitcher mKeyguardUserSwitcher;
     private KeyguardStatusBarView mKeyguardStatusBar;
     protected QSContainer mQsContainer;
-    private DensityContainer mQsDensityContainer;
+    private AutoReinflateContainer mQsAutoReinflateContainer;
     private KeyguardStatusView mKeyguardStatusView;
     private TextView mClockView;
     private View mReserveNotificationSpace;
@@ -219,8 +219,9 @@
         super.onFinishInflate();
         mKeyguardStatusBar = (KeyguardStatusBarView) findViewById(R.id.keyguard_header);
         mKeyguardStatusView = (KeyguardStatusView) findViewById(R.id.keyguard_status_view);
-        mQsDensityContainer = (DensityContainer) findViewById(R.id.qs_density_container);
-        mQsDensityContainer.addInflateListener(new InflateListener() {
+        mQsAutoReinflateContainer =
+                (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
+        mQsAutoReinflateContainer.addInflateListener(new InflateListener() {
             @Override
             public void onInflated(View v) {
                 mQsContainer = (QSContainer) v.findViewById(R.id.quick_settings_container);
@@ -280,11 +281,11 @@
         int panelWidth = getResources().getDimensionPixelSize(R.dimen.notification_panel_width);
         int panelGravity = getResources().getInteger(R.integer.notification_panel_layout_gravity);
         FrameLayout.LayoutParams lp =
-                (FrameLayout.LayoutParams) mQsDensityContainer.getLayoutParams();
+                (FrameLayout.LayoutParams) mQsAutoReinflateContainer.getLayoutParams();
         if (lp.width != panelWidth) {
             lp.width = panelWidth;
             lp.gravity = panelGravity;
-            mQsDensityContainer.setLayoutParams(lp);
+            mQsAutoReinflateContainer.setLayoutParams(lp);
             mQsContainer.post(mUpdateHeader);
         }
 
@@ -790,8 +791,8 @@
     }
 
     private boolean isInQsArea(float x, float y) {
-        return (x >= mQsDensityContainer.getX()
-                && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth())
+        return (x >= mQsAutoReinflateContainer.getX()
+                && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth())
                 && (y <= mNotificationStackScroller.getBottomMostNotificationBottom()
                 || y <= mQsContainer.getY() + mQsContainer.getHeight());
     }
@@ -1339,8 +1340,8 @@
             return false;
         }
         View header = mKeyguardShowing ? mKeyguardStatusBar : mQsContainer.getHeader();
-        boolean onHeader = x >= mQsDensityContainer.getX()
-                && x <= mQsDensityContainer.getX() + mQsDensityContainer.getWidth()
+        boolean onHeader = x >= mQsAutoReinflateContainer.getX()
+                && x <= mQsAutoReinflateContainer.getX() + mQsAutoReinflateContainer.getWidth()
                 && y >= header.getTop() && y <= header.getBottom();
         if (mQsExpanded) {
             return onHeader || (yDiff < 0 && isInQsArea(x, y));
@@ -2227,7 +2228,7 @@
 
     protected void setVerticalPanelTranslation(float translation) {
         mNotificationStackScroller.setTranslationX(translation);
-        mQsDensityContainer.setTranslationX(translation);
+        mQsAutoReinflateContainer.setTranslationX(translation);
     }
 
     protected void updateStackHeight(float stackHeight) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
index 35fb2a5..36e59db 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationsQuickSettingsContainer.java
@@ -24,7 +24,7 @@
 import android.view.ViewStub;
 import android.view.WindowInsets;
 import android.widget.FrameLayout;
-import com.android.systemui.DensityContainer;
+import com.android.systemui.AutoReinflateContainer;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSContainer;
 import com.android.systemui.qs.customize.QSCustomizer;
@@ -33,10 +33,10 @@
  * The container with notification stack scroller and quick settings inside.
  */
 public class NotificationsQuickSettingsContainer extends FrameLayout
-        implements ViewStub.OnInflateListener, DensityContainer.InflateListener {
+        implements ViewStub.OnInflateListener, AutoReinflateContainer.InflateListener {
 
 
-    private DensityContainer mQsContainer;
+    private AutoReinflateContainer mQsContainer;
     private View mUserSwitcher;
     private View mStackScroller;
     private View mKeyguardStatusBar;
@@ -54,7 +54,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mQsContainer = (DensityContainer) findViewById(R.id.qs_density_container);
+        mQsContainer = (AutoReinflateContainer) findViewById(R.id.qs_auto_reinflate_container);
         mQsContainer.addInflateListener(this);
         mStackScroller = findViewById(R.id.notification_stack_scroller);
         mStackScrollerMargin = ((LayoutParams) mStackScroller.getLayoutParams()).bottomMargin;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 712f814..c36c482 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -103,10 +103,10 @@
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
 import com.android.keyguard.ViewMediatorCallback;
+import com.android.systemui.AutoReinflateContainer;
+import com.android.systemui.AutoReinflateContainer.InflateListener;
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.DemoMode;
-import com.android.systemui.DensityContainer;
-import com.android.systemui.DensityContainer.InflateListener;
 import com.android.systemui.EventLogConstants;
 import com.android.systemui.EventLogTags;
 import com.android.systemui.Interpolators;
@@ -871,8 +871,8 @@
         }
 
         // Set up the quick settings tile panel
-        DensityContainer container = (DensityContainer) mStatusBarWindow.findViewById(
-                R.id.qs_density_container);
+        AutoReinflateContainer container = (AutoReinflateContainer) mStatusBarWindow.findViewById(
+                R.id.qs_auto_reinflate_container);
         if (container != null) {
             final QSTileHost qsh = SystemUIFactory.getInstance().createQSTileHost(mContext, this,
                     mBluetoothController, mLocationController, mRotationLockController,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
index 3293964..66152fc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/Clock.java
@@ -61,6 +61,7 @@
     private Calendar mCalendar;
     private String mClockFormatString;
     private SimpleDateFormat mClockFormat;
+    private SimpleDateFormat mContentDescriptionFormat;
     private Locale mLocale;
 
     private static final int AM_PM_STYLE_NORMAL  = 0;
@@ -158,6 +159,7 @@
         if (mDemoMode) return;
         mCalendar.setTimeInMillis(System.currentTimeMillis());
         setText(getSmallTime());
+        setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
     }
 
     @Override
@@ -207,6 +209,7 @@
                 ? is24 ? d.timeFormat_Hms : d.timeFormat_hms
                 : is24 ? d.timeFormat_Hm : d.timeFormat_hm;
         if (!format.equals(mClockFormatString)) {
+            mContentDescriptionFormat = new SimpleDateFormat(format);
             /*
              * Search for an unquoted "a" in the format string, so we can
              * add dummy characters around it to let us find it again after
@@ -295,6 +298,7 @@
                 mCalendar.set(Calendar.MINUTE, mm);
             }
             setText(getSmallTime());
+            setContentDescription(mContentDescriptionFormat.format(mCalendar.getTime()));
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 557f166..ecd1772 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -105,7 +105,6 @@
                 return false;
             }
         });
-        mEditText.setOnClickListener(this);
         mEditText.addTextChangedListener(this);
         mEditText.setInnerFocusable(false);
         mEditText.mRemoteInputView = this;
@@ -148,15 +147,19 @@
 
     @Override
     public void onClick(View v) {
-        if (v == mEditText) {
-            if (!mEditText.isFocusable()) {
-                focus();
-            }
-        } else if (v == mSendButton) {
+        if (v == mSendButton) {
             sendRemoteInput();
         }
     }
 
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        super.onTouchEvent(event);
+
+        // We never want for a touch to escape to an outer view or one we covered.
+        return true;
+    }
+
     public void onDefocus() {
         mController.removeRemoteInput(mEntry);
         mEntry.remoteInputText = mEditText.getText();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
index c65415e..bcf2f67 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
@@ -92,8 +92,8 @@
         TypedArray typedArray =
             context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
 
-        mButtonImageView.setImageDrawable(typedArray.getDrawable(0));
-        mDescriptionTextView.setText(typedArray.getText(1));
+        setImageResource(typedArray.getResourceId(0, 0));
+        setText(typedArray.getResourceId(1, 0));
 
         typedArray.recycle();
     }
@@ -132,6 +132,7 @@
      * Sets the text for description the with the given resource id.
      */
     public void setText(int resId) {
+        mButtonImageView.setContentDescription(getContext().getString(resId));
         mDescriptionTextView.setText(resId);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
index 5febb9b..d7efca7 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipManager.java
@@ -276,9 +276,6 @@
     void movePipToFullscreen() {
         mState = STATE_NO_PIP;
         mPipTaskId = TASK_ID_NO_PIP;
-        for (int i = mListeners.size() - 1; i >= 0; --i) {
-            mListeners.get(i).onMoveToFullscreen();
-        }
         resizePinnedStack(mState);
     }
 
@@ -638,6 +635,11 @@
         public void onPinnedStackAnimationEnded() {
             if (DEBUG) Log.d(TAG, "onPinnedStackAnimationEnded()");
             switch (mState) {
+                case STATE_NO_PIP:
+                    for (int i = mListeners.size() - 1; i >= 0; --i) {
+                        mListeners.get(i).onMoveToFullscreen();
+                    }
+                    break;
                 case STATE_PIP_OVERLAY:
                     if (!mPipRecentsOverlayManager.isRecentsShown()) {
                         showPipOverlay();
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index d75561b..dd12360 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -21,6 +21,7 @@
 import android.util.Log;
 import android.view.LayoutInflater;
 import android.view.View;
+import android.view.accessibility.AccessibilityEvent;
 import android.view.WindowManager.LayoutParams;
 import android.view.WindowManager;
 
@@ -133,7 +134,7 @@
      */
     public void requestFocus(boolean allowRecentsFocusable) {
         mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
-        if (!mIsRecentsShown || mIsPipFocusedInRecent) {
+        if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || mIsPipFocusedInRecent) {
             return;
         }
         mIsPipFocusedInRecent = true;
@@ -141,6 +142,7 @@
 
         mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
         mPipControlsView.requestFocus();
+        mPipControlsView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
         mPipControlsView.startFocusGainAnimation();
     }
 
@@ -151,7 +153,7 @@
      * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
      */
     public void clearFocus() {
-        if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
+        if (!mIsPipRecentsOverlayShown || !mIsRecentsShown || !mIsPipFocusedInRecent) {
             return;
         }
         if (!mRecentsView.hasFocus()) {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index de70139..65b93c7 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -18,7 +18,9 @@
 
 import android.accessibilityservice.AccessibilityServiceInfo;
 import android.animation.LayoutTransition;
+import android.animation.ObjectAnimator;
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.annotation.SuppressLint;
 import android.app.Dialog;
 import android.app.KeyguardManager;
@@ -59,6 +61,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityManager;
 import android.view.accessibility.AccessibilityManager.AccessibilityStateChangeListener;
+import android.view.animation.DecelerateInterpolator;
 import android.widget.ImageButton;
 import android.widget.LinearLayout;
 import android.widget.SeekBar;
@@ -92,6 +95,7 @@
     public static final String SHOW_FULL_ZEN = "sysui_show_full_zen";
 
     private static final long USER_ATTEMPT_GRACE_PERIOD = 1000;
+    private static final int UPDATE_ANIMATION_DURATION = 80;
 
     private final Context mContext;
     private final H mHandler = new H();
@@ -106,6 +110,7 @@
     private final SparseBooleanArray mDynamic = new SparseBooleanArray();
     private final KeyguardManager mKeyguard;
     private final AudioManager mAudioManager;
+    private final AccessibilityManager mAccessibilityMgr;
     private int mExpandButtonAnimationDuration;
     private ZenFooter mZenFooter;
     private final LayoutTransition mLayoutTransition;
@@ -147,6 +152,7 @@
         mSpTexts = new SpTexts(mContext);
         mKeyguard = (KeyguardManager) context.getSystemService(Context.KEYGUARD_SERVICE);
         mAudioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+        mAccessibilityMgr = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
         mActiveSliderTint = loadColorStateList(R.color.system_accent_color);
         mInactiveSliderTint = loadColorStateList(R.color.volume_slider_inactive);
         mLayoutTransition = new LayoutTransition();
@@ -369,6 +375,14 @@
         writer.println(mAccessibility.mFeedbackEnabled);
     }
 
+    private static int getImpliedLevel(SeekBar seekBar, int progress) {
+        final int m = seekBar.getMax();
+        final int n = m / 100 - 1;
+        final int level = progress == 0 ? 0
+                : progress == m ? (m / 100) : (1 + (int)((progress / (float) m) * n));
+        return level;
+    }
+
     @SuppressLint("InflateParams")
     private void initRow(final VolumeRow row, final int stream, int iconRes, int iconMuteRes,
             boolean important) {
@@ -496,6 +510,15 @@
                 setExpandedH(false);
             }
         });
+        if (mAccessibilityMgr.isEnabled()) {
+            AccessibilityEvent event =
+                    AccessibilityEvent.obtain(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            event.setPackageName(mContext.getPackageName());
+            event.setClassName(CustomDialog.class.getSuperclass().getName());
+            event.getText().add(mContext.getString(
+                    R.string.volume_dialog_accessibility_dismissed_message));
+            mAccessibilityMgr.sendAccessibilityEvent(event);
+        }
         Events.writeEvent(mContext, Events.EVENT_DISMISS_DIALOG, reason);
         mController.notifyVisible(false);
         synchronized (mSafetyWarningLock) {
@@ -707,7 +730,7 @@
                 : false;
 
         // update slider max
-        final int max = ss.levelMax;
+        final int max = ss.levelMax * 100;
         if (max != row.slider.getMax()) {
             row.slider.setMax(max);
         }
@@ -824,7 +847,8 @@
         if (row.tracking) {
             return;  // don't update if user is sliding
         }
-        final int level = row.slider.getProgress();
+        final int progress = row.slider.getProgress();
+        final int level = getImpliedLevel(row.slider, progress);
         final boolean rowVisible = row.view.getVisibility() == View.VISIBLE;
         final boolean inGracePeriod = (SystemClock.uptimeMillis() - row.userAttempt)
                 < USER_ATTEMPT_GRACE_PERIOD;
@@ -840,7 +864,33 @@
                 return;  // don't clamp if visible
             }
         }
-        row.slider.setProgress(vlevel, true);
+        final int newProgress = vlevel * 100;
+        if (progress != newProgress) {
+            if (mShowing && rowVisible) {
+                // animate!
+                if (row.anim != null && row.anim.isRunning()
+                        && row.animTargetProgress == newProgress) {
+                    return;  // already animating to the target progress
+                }
+                // start/update animation
+                if (row.anim == null) {
+                    row.anim = ObjectAnimator.ofInt(row.slider, "progress", progress, newProgress);
+                    row.anim.setInterpolator(new DecelerateInterpolator());
+                } else {
+                    row.anim.cancel();
+                    row.anim.setIntValues(progress, newProgress);
+                }
+                row.animTargetProgress = newProgress;
+                row.anim.setDuration(UPDATE_ANIMATION_DURATION);
+                row.anim.start();
+            } else {
+                // update slider directly to clamped value
+                if (row.anim != null) {
+                    row.anim.cancel();
+                }
+                row.slider.setProgress(newProgress);
+            }
+        }
     }
 
     private void recheckH(VolumeRow row) {
@@ -1044,6 +1094,27 @@
             }
             return false;
         }
+
+        @Override
+        public boolean dispatchPopulateAccessibilityEvent(@NonNull AccessibilityEvent event) {
+            event.setClassName(getClass().getSuperclass().getName());
+            event.setPackageName(mContext.getPackageName());
+
+            ViewGroup.LayoutParams params = getWindow().getAttributes();
+            boolean isFullScreen = (params.width == ViewGroup.LayoutParams.MATCH_PARENT) &&
+                    (params.height == ViewGroup.LayoutParams.MATCH_PARENT);
+            event.setFullScreen(isFullScreen);
+
+            if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
+                if (mShowing) {
+                    event.getText().add(mContext.getString(
+                            R.string.volume_dialog_accessibility_shown_message,
+                            getActiveRow().ss.name));
+                    return true;
+                }
+            }
+            return false;
+        }
     }
 
     private final class VolumeSeekBarChangeListener implements OnSeekBarChangeListener {
@@ -1060,19 +1131,20 @@
                     + " onProgressChanged " + progress + " fromUser=" + fromUser);
             if (!fromUser) return;
             if (mRow.ss.levelMin > 0) {
-                final int minProgress = mRow.ss.levelMin;
+                final int minProgress = mRow.ss.levelMin * 100;
                 if (progress < minProgress) {
                     seekBar.setProgress(minProgress);
                     progress = minProgress;
                 }
             }
-            if (mRow.ss.level != progress || mRow.ss.muted && progress > 0) {
+            final int userLevel = getImpliedLevel(seekBar, progress);
+            if (mRow.ss.level != userLevel || mRow.ss.muted && userLevel > 0) {
                 mRow.userAttempt = SystemClock.uptimeMillis();
-                if (mRow.requestedLevel != progress) {
-                    mController.setStreamVolume(mRow.stream, progress);
-                    mRow.requestedLevel = progress;
+                if (mRow.requestedLevel != userLevel) {
+                    mController.setStreamVolume(mRow.stream, userLevel);
+                    mRow.requestedLevel = userLevel;
                     Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_CHANGED, mRow.stream,
-                            progress);
+                            userLevel);
                 }
             }
         }
@@ -1089,7 +1161,7 @@
             if (D.BUG) Log.d(TAG, "onStopTrackingTouch"+ " " + mRow.stream);
             mRow.tracking = false;
             mRow.userAttempt = SystemClock.uptimeMillis();
-            final int userLevel = seekBar.getProgress();
+            final int userLevel = getImpliedLevel(seekBar, seekBar.getProgress());
             Events.writeEvent(mContext, Events.EVENT_TOUCH_LEVEL_DONE, mRow.stream, userLevel);
             if (mRow.ss.level != userLevel) {
                 mHandler.sendMessageDelayed(mHandler.obtainMessage(H.RECHECK, mRow),
@@ -1099,16 +1171,13 @@
     }
 
     private final class Accessibility extends AccessibilityDelegate {
-        private AccessibilityManager mMgr;
         private boolean mFeedbackEnabled;
 
         public void init() {
-            mMgr = (AccessibilityManager) mContext.getSystemService(Context.ACCESSIBILITY_SERVICE);
             mDialogView.addOnAttachStateChangeListener(new OnAttachStateChangeListener() {
                 @Override
                 public void onViewDetachedFromWindow(View v) {
                     if (D.BUG) Log.d(TAG, "onViewDetachedFromWindow");
-                    // noop
                 }
 
                 @Override
@@ -1118,12 +1187,13 @@
                 }
             });
             mDialogView.setAccessibilityDelegate(this);
-            mMgr.addAccessibilityStateChangeListener(new AccessibilityStateChangeListener() {
-                @Override
-                public void onAccessibilityStateChanged(boolean enabled) {
-                    updateFeedbackEnabled();
-                }
-            });
+            mAccessibilityMgr.addAccessibilityStateChangeListener(
+                    new AccessibilityStateChangeListener() {
+                        @Override
+                        public void onAccessibilityStateChanged(boolean enabled) {
+                            updateFeedbackEnabled();
+                        }
+                    });
             updateFeedbackEnabled();
         }
 
@@ -1141,7 +1211,7 @@
         private boolean computeFeedbackEnabled() {
             // are there any enabled non-generic a11y services?
             final List<AccessibilityServiceInfo> services =
-                    mMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
+                    mAccessibilityMgr.getEnabledAccessibilityServiceList(FEEDBACK_ALL_MASK);
             for (AccessibilityServiceInfo asi : services) {
                 if (asi.feedbackType != 0 && asi.feedbackType != FEEDBACK_GENERIC) {
                     return true;
@@ -1169,6 +1239,8 @@
         private ColorStateList cachedSliderTint;
         private int iconState;  // from Events
         private boolean cachedShowHeaders = VolumePrefs.DEFAULT_SHOW_HEADERS;
+        private ObjectAnimator anim;  // slider progress animation for non-touch-related updates
+        private int animTargetProgress;
         private int lastAudibleLevel = 1;
     }
 
diff --git a/packages/WallpaperBackup/Android.mk b/packages/WallpaperBackup/Android.mk
new file mode 100644
index 0000000..cf04249
--- /dev/null
+++ b/packages/WallpaperBackup/Android.mk
@@ -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.
+#
+
+LOCAL_PATH := $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-java-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.flags
+
+LOCAL_PACKAGE_NAME := WallpaperBackup
+LOCAL_CERTIFICATE := platform
+LOCAL_PRIVILEGED_MODULE := false
+
+include $(BUILD_PACKAGE)
+
+########################
+include $(call all-makefiles-under,$(LOCAL_PATH))
+
diff --git a/packages/WallpaperBackup/AndroidManifest.xml b/packages/WallpaperBackup/AndroidManifest.xml
new file mode 100644
index 0000000..b8cea20
--- /dev/null
+++ b/packages/WallpaperBackup/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+ * Copyright (c) 2016 Google Inc.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.android.wallpaperbackup"
+    android:sharedUserId="android.uid.system" >
+
+    <application android:allowClearUserData="false"
+                 android:process="system"
+                 android:killAfterRestore="false"
+                 android:allowBackup="true"
+                 android:backupAgent=".WallpaperBackupAgent"
+                 android:fullBackupOnly="true" >
+    </application>
+</manifest>
diff --git a/packages/WallpaperBackup/proguard.flags b/packages/WallpaperBackup/proguard.flags
new file mode 100644
index 0000000..247e6ef
--- /dev/null
+++ b/packages/WallpaperBackup/proguard.flags
@@ -0,0 +1 @@
+-keep class com.android.wallpaperbackup.WallpaperBackupAgent
diff --git a/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
new file mode 100644
index 0000000..2f79079
--- /dev/null
+++ b/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java
@@ -0,0 +1,164 @@
+/*
+ * 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.wallpaperbackup;
+
+import android.app.WallpaperManager;
+import android.app.backup.BackupAgent;
+import android.app.backup.BackupDataInput;
+import android.app.backup.BackupDataOutput;
+import android.app.backup.FullBackupDataOutput;
+import android.content.Context;
+import android.os.Environment;
+import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
+import android.system.Os;
+import android.util.Slog;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+
+public class WallpaperBackupAgent extends BackupAgent {
+    private static final String TAG = "WallpaperBackup";
+    private static final boolean DEBUG = false;
+
+    // NB: must be kept in sync with WallpaperManagerService but has no
+    // compile-time visiblity.
+
+    // Target filenames within the system's wallpaper directory
+    static final String WALLPAPER = "wallpaper_orig";
+    static final String WALLPAPER_INFO = "wallpaper_info.xml";
+
+    // Names of our local-data stage files/links
+    static final String IMAGE_STAGE = "wallpaper-stage";
+    static final String INFO_STAGE = "wallpaper-info-stage";
+    static final String EMPTY_SENTINEL = "empty";
+
+    private File mWallpaperInfo;    // wallpaper metadata file
+    private File mWallpaperFile;    // primary wallpaper image file
+
+    private WallpaperManager mWm;
+
+    @Override
+    public void onCreate() {
+        if (DEBUG) {
+            Slog.v(TAG, "onCreate()");
+        }
+
+        File wallpaperDir = Environment.getUserSystemDirectory(UserHandle.USER_SYSTEM);
+        mWallpaperInfo = new File(wallpaperDir, WALLPAPER_INFO);
+        mWallpaperFile = new File(wallpaperDir, WALLPAPER);
+        mWm = (WallpaperManager) getSystemService(Context.WALLPAPER_SERVICE);
+    }
+
+    @Override
+    public void onFullBackup(FullBackupDataOutput data) throws IOException {
+        // To avoid data duplication and disk churn, use links as the stage.
+        final File filesDir = getFilesDir();
+        final File infoStage = new File(filesDir, INFO_STAGE);
+        final File imageStage = new File (filesDir, IMAGE_STAGE);
+        final File empty = new File (filesDir, EMPTY_SENTINEL);
+
+        try {
+            // We always back up this 'empty' file to ensure that the absence of
+            // storable wallpaper imagery still produces a non-empty backup data
+            // stream, otherwise it'd simply be ignored in preflight.
+            FileOutputStream touch = new FileOutputStream(empty);
+            touch.close();
+            fullBackupFile(empty, data);
+
+            // only back up the wallpaper if we've been told it's allowed
+            if (mWm.isWallpaperBackupEligible()) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper is backup-eligible; linking & writing");
+                }
+                Os.link(mWallpaperInfo.getCanonicalPath(), infoStage.getCanonicalPath());
+                fullBackupFile(infoStage, data);
+                Os.link(mWallpaperFile.getCanonicalPath(), imageStage.getCanonicalPath());
+                fullBackupFile(imageStage, data);
+            } else {
+                if (DEBUG) {
+                    Slog.v(TAG, "Wallpaper not backup-eligible; writing no data");
+                }
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to back up wallpaper: " + e.getMessage());
+        } finally {
+            if (DEBUG) {
+                Slog.v(TAG, "Removing backup stage links");
+            }
+            infoStage.delete();
+            imageStage.delete();
+        }
+    }
+
+    // We use the default onRestoreFile() implementation that will recreate our stage files,
+    // then postprocess in onRestoreFinished() to move them on top of the live data.
+    //
+    // NOTE: this relies on our local files dir being on the same filesystem as the live
+    // system wallpaper data.  If this is not the case then an actual copy operation will
+    // be needed.
+    @Override
+    public void onRestoreFinished() {
+        if (DEBUG) {
+            Slog.v(TAG, "onRestoreFinished()");
+        }
+        final File infoStage = new File(getFilesDir(), INFO_STAGE);
+        final File imageStage = new File (getFilesDir(), IMAGE_STAGE);
+
+        try {
+            // It is valid for the imagery to be absent; it means that we were not permitted
+            // to back up the original image on the source device.
+            if (imageStage.exists()) {
+                if (DEBUG) {
+                    Slog.v(TAG, "Got restored wallpaper; renaming into place");
+                }
+                // Rename the image file into place last because that is the trigger for
+                // the wallpaper observer to generate a new crop/scale
+                Os.rename(infoStage.getCanonicalPath(), mWallpaperInfo.getCanonicalPath());
+                Os.rename(imageStage.getCanonicalPath(), mWallpaperFile.getCanonicalPath());
+            }
+        } catch (Exception e) {
+            Slog.e(TAG, "Unable to restore wallpaper: " + e.getMessage());
+            mWm.clearWallpaper(WallpaperManager.FLAG_SYSTEM, UserHandle.USER_SYSTEM);
+        } finally {
+            // These "should" not exist because of the renames, but make sure
+            // in case of errors/exceptions/etc.
+            if (DEBUG) {
+                Slog.v(TAG, "Removing restore stage files");
+            }
+            infoStage.delete();
+            imageStage.delete();
+        }
+    }
+
+    //
+    // Key/value API: abstract, so required, but not used
+    //
+
+    @Override
+    public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
+            ParcelFileDescriptor newState) throws IOException {
+        // Intentionally blank
+    }
+
+    @Override
+    public void onRestore(BackupDataInput data, int appVersionCode, ParcelFileDescriptor newState)
+            throws IOException {
+        // Intentionally blank
+    }
+}
\ No newline at end of file
diff --git a/rs/java/android/renderscript/Allocation.java b/rs/java/android/renderscript/Allocation.java
index 04ea8e5..c0ea132 100644
--- a/rs/java/android/renderscript/Allocation.java
+++ b/rs/java/android/renderscript/Allocation.java
@@ -392,8 +392,6 @@
 
     protected void finalize() throws Throwable {
         RenderScript.registerNativeFree.invoke(RenderScript.sRuntime, mSize);
-        // Set mType null to avoid double-destroying it in case its finalizer races ahead
-        mType = null;
         super.finalize();
     }
 
@@ -2615,7 +2613,6 @@
 
         if (mType != null && mOwningType) {
             mType.destroy();
-            mType = null;
         }
 
         super.destroy();
diff --git a/rs/java/android/renderscript/ScriptGroup.java b/rs/java/android/renderscript/ScriptGroup.java
index 0d10c6d..e0bdbfc 100644
--- a/rs/java/android/renderscript/ScriptGroup.java
+++ b/rs/java/android/renderscript/ScriptGroup.java
@@ -1066,19 +1066,12 @@
      */
     public void destroy() {
         super.destroy();
-        for(Closure c : mClosures) {
-            c.destroy();
-        }
-    }
-
-    protected void finalize() throws Throwable {
-        // Clear out the list mClosures to avoid double-destroying the closures,
-        // in case their finalizers race ahead.
+        // ScriptGroup created using the old Builder class does not
+        // initialize the field mClosures
         if (mClosures != null) {
-            // ScriptGroup created using the old Builder class does not
-            // initialize the field mClosures
-            mClosures.clear();
+            for (Closure c : mClosures) {
+                c.destroy();
+            }
         }
-        super.finalize();
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 4d7f82d..2a7d945 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -20,6 +20,7 @@
 import android.os.PowerManager;
 import android.util.Pools.SimplePool;
 import android.util.Slog;
+import android.util.SparseBooleanArray;
 import android.view.Choreographer;
 import android.view.InputDevice;
 import android.view.InputEvent;
@@ -637,10 +638,10 @@
     }
 
     /**
-     * Keeps state of stream of events from a keyboard device.
+     * Keeps state of streams of events from all keyboard devices.
      */
     private static class KeyboardEventStreamState extends EventStreamState {
-        private boolean mEventSequenceStarted;
+        private SparseBooleanArray mEventSequenceStartedMap = new SparseBooleanArray();
 
         public KeyboardEventStreamState() {
             reset();
@@ -649,17 +650,35 @@
         @Override
         final public void reset() {
             super.reset();
-            mEventSequenceStarted = false;
+            mEventSequenceStartedMap.clear();
         }
 
+        /*
+         * Key events from different devices may be interleaved. For example, the volume up and
+         * down keys can come from different device IDs.
+         */
+        @Override
+        public boolean updateDeviceId(int deviceId) {
+            return false;
+        }
+
+        // We manage all device ids simultaneously; there is no concept of validity.
+        @Override
+        public boolean deviceIdValid() {
+            return true;
+        }
+
+
         @Override
         final public boolean shouldProcessKeyEvent(KeyEvent event) {
-            // Wait for a down key event to start processing.
-            if (mEventSequenceStarted) {
+            // For each keyboard device, wait for a down event from a device to start processing
+            int deviceId = event.getDeviceId();
+            if (mEventSequenceStartedMap.get(deviceId, false)) {
                 return true;
             }
-            mEventSequenceStarted = event.getAction() == KeyEvent.ACTION_DOWN;
-            return mEventSequenceStarted;
+            boolean shouldProcess = event.getAction() == KeyEvent.ACTION_DOWN;
+            mEventSequenceStartedMap.put(deviceId, shouldProcess);
+            return shouldProcess;
         }
     }
 }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 71506be..b069361 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -71,7 +71,8 @@
 import android.net.RouteInfo;
 import android.net.UidRange;
 import android.net.Uri;
-import android.net.metrics.ConnectivityServiceChangeEvent;
+import android.net.metrics.DefaultNetworkEvent;
+import android.net.metrics.NetworkEvent;
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
@@ -2109,6 +2110,7 @@
 
     private void linger(NetworkAgentInfo nai) {
         nai.lingering = true;
+        NetworkEvent.logEvent(nai.network.netId, NetworkEvent.NETWORK_LINGER);
         nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_LINGER);
         notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOSING);
     }
@@ -2122,6 +2124,7 @@
         nai.networkLingered.clear();
         if (!nai.lingering) return;
         nai.lingering = false;
+        NetworkEvent.logEvent(nai.network.netId, NetworkEvent.NETWORK_UNLINGER);
         if (VDBG) log("Canceling linger of " + nai.name());
         nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_CONNECTED);
     }
@@ -2217,7 +2220,7 @@
             rematchAllNetworksAndRequests(null, 0);
             if (wasDefault && getDefaultNetwork() == null) {
                 // Log that we lost the default network and there is no replacement.
-                logConnectivityServiceChangeEvent(null, nai);
+                logDefaultNetworkEvent(null, nai);
             }
             if (nai.created) {
                 // Tell netd to clean up the configuration for this network
@@ -2330,6 +2333,18 @@
             if (VDBG || (DBG && nri.isRequest())) log("releasing NetworkRequest " + request);
             nri.unlinkDeathRecipient();
             mNetworkRequests.remove(request);
+            synchronized (mUidToNetworkRequestCount) {
+                int requests = mUidToNetworkRequestCount.get(nri.mUid, 0);
+                if (requests < 1) {
+                    Slog.wtf(TAG, "BUG: too small request count " + requests + " for UID " +
+                            nri.mUid);
+                } else if (requests == 1) {
+                    mUidToNetworkRequestCount.removeAt(
+                            mUidToNetworkRequestCount.indexOfKey(nri.mUid));
+                } else {
+                    mUidToNetworkRequestCount.put(nri.mUid, requests - 1);
+                }
+            }
             mNetworkRequestInfoLogs.log("RELEASE " + nri);
             if (nri.isRequest()) {
                 // Find all networks that are satisfying this request and remove the request
@@ -3677,6 +3692,11 @@
     private final HashMap<NetworkRequest, NetworkRequestInfo> mNetworkRequests =
             new HashMap<NetworkRequest, NetworkRequestInfo>();
 
+    private static final int MAX_NETWORK_REQUESTS_PER_UID = 100;
+    // Map from UID to number of NetworkRequests that UID has filed.
+    @GuardedBy("mUidToNetworkRequestCount")
+    private final SparseIntArray mUidToNetworkRequestCount = new SparseIntArray();
+
     private static class NetworkFactoryInfo {
         public final String name;
         public final Messenger messenger;
@@ -3737,6 +3757,7 @@
             mPid = getCallingPid();
             mUid = getCallingUid();
             mType = type;
+            enforceRequestCountLimit();
         }
 
         NetworkRequestInfo(Messenger m, NetworkRequest r, IBinder binder, NetworkRequestType type) {
@@ -3748,6 +3769,7 @@
             mUid = getCallingUid();
             mType = type;
             mPendingIntent = null;
+            enforceRequestCountLimit();
 
             try {
                 mBinder.linkToDeath(this, 0);
@@ -3756,6 +3778,16 @@
             }
         }
 
+        private void enforceRequestCountLimit() {
+            synchronized (mUidToNetworkRequestCount) {
+                int networkRequests = mUidToNetworkRequestCount.get(mUid, 0) + 1;
+                if (networkRequests >= MAX_NETWORK_REQUESTS_PER_UID) {
+                    throw new IllegalArgumentException("Too many NetworkRequests filed");
+                }
+                mUidToNetworkRequestCount.put(mUid, networkRequests);
+            }
+        }
+
         private String typeString() {
             switch (mType) {
                 case LISTEN: return "Listen";
@@ -4452,8 +4484,7 @@
         handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
         updateTcpBufferSizes(newNetwork);
         setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
-
-        logConnectivityServiceChangeEvent(newNetwork, prevNetwork);
+        logDefaultNetworkEvent(newNetwork, prevNetwork);
     }
 
     // Handles a network appearing or improving its score.
@@ -5075,21 +5106,24 @@
         return new NetworkMonitor(context, handler, nai, defaultRequest);
     }
 
-    private static void logConnectivityServiceChangeEvent(
-            NetworkAgentInfo next, NetworkAgentInfo prev) {
-        final int newNetId = (next == null) ? NETID_UNSET : next.network.netId;
-        final int[] newTransportTypes = (next == null)
-                ? new int[0]
-                : next.networkCapabilities.getTransportTypes();
+    private static void logDefaultNetworkEvent(NetworkAgentInfo newNai, NetworkAgentInfo prevNai) {
+        int newNetid = NETID_UNSET;
+        int prevNetid = NETID_UNSET;
+        int[] transports = new int[0];
+        boolean hadIPv4 = false;
+        boolean hadIPv6 = false;
 
-        final int oldNetId = (prev == null) ? NETID_UNSET : prev.network.netId;
-        final boolean hadIPv4 = (prev != null) &&
-                prev.linkProperties.hasIPv4Address() &&
-                prev.linkProperties.hasIPv4DefaultRoute();
-        final boolean hadIPv6 = (prev != null) &&
-                prev.linkProperties.hasGlobalIPv6Address() &&
-                prev.linkProperties.hasIPv6DefaultRoute();
-        ConnectivityServiceChangeEvent.logEvent(newNetId, newTransportTypes,
-                oldNetId, hadIPv4, hadIPv6);
+        if (newNai != null) {
+            newNetid = newNai.network.netId;
+            transports = newNai.networkCapabilities.getTransportTypes();
+        }
+        if (prevNai != null) {
+            prevNetid = prevNai.network.netId;
+            final LinkProperties lp = prevNai.linkProperties;
+            hadIPv4 = lp.hasIPv4Address() && lp.hasIPv4DefaultRoute();
+            hadIPv6 = lp.hasGlobalIPv6Address() && lp.hasIPv6DefaultRoute();
+        }
+
+        DefaultNetworkEvent.logEvent(newNetid, transports, prevNetid, hadIPv4, hadIPv6);
     }
 }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 6c05173..bc9f69e 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -1048,7 +1048,13 @@
     private void changeUserKey(int userId, byte[] token, byte[] secret)
             throws RemoteException {
         final UserInfo userInfo = UserManager.get(mContext).getUserInfo(userId);
-        getMountService().changeUserKey(userId, userInfo.serialNumber, token, null, secret);
+        final IMountService mountService = getMountService();
+        final long callingId = Binder.clearCallingIdentity();
+        try {
+            mountService.changeUserKey(userId, userInfo.serialNumber, token, null, secret);
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/NativeDaemonConnector.java b/services/core/java/com/android/server/NativeDaemonConnector.java
index 6009984..f5f7732 100644
--- a/services/core/java/com/android/server/NativeDaemonConnector.java
+++ b/services/core/java/com/android/server/NativeDaemonConnector.java
@@ -41,6 +41,7 @@
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.concurrent.ArrayBlockingQueue;
 import java.util.concurrent.BlockingQueue;
+import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 import java.util.LinkedList;
 
@@ -344,6 +345,30 @@
     }
 
     /**
+     * Method that waits until all asychronous notifications sent by the native daemon have
+     * been processed. This method must not be called on the notification thread or an
+     * exception will be thrown.
+     */
+    public void waitForCallbacks() {
+        if (Thread.currentThread() == mLooper.getThread()) {
+            throw new IllegalStateException("Must not call this method on callback thread");
+        }
+
+        final CountDownLatch latch = new CountDownLatch(1);
+        mCallbackHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                latch.countDown();
+            }
+        });
+        try {
+            latch.await();
+        } catch (InterruptedException e) {
+            Slog.wtf(TAG, "Interrupted while waiting for unsolicited response handling", e);
+        }
+    }
+
+    /**
      * Issue the given command to the native daemon and return a single expected
      * response.
      *
diff --git a/services/core/java/com/android/server/NetworkManagementService.java b/services/core/java/com/android/server/NetworkManagementService.java
index fffd850..7458898 100644
--- a/services/core/java/com/android/server/NetworkManagementService.java
+++ b/services/core/java/com/android/server/NetworkManagementService.java
@@ -1507,6 +1507,11 @@
         } catch (NativeDaemonConnectorException e) {
             throw e.rethrowAsParcelableException();
         }
+
+        // Ensure that before we return from this command, any asynchronous
+        // notifications generated before the command completed have been
+        // processed by all NetworkManagementEventObservers.
+        mConnector.waitForCallbacks();
     }
 
     @Override
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 4791818..87dedc9 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -4696,26 +4696,20 @@
             ceHelper.getWritableDatabase();
             ceHelper.close();
             if (removeOldDb) {
-                // TODO STOPSHIP - backup file during testing. Remove file before the release
-                Log.i(TAG, "Migration complete - creating backup of old db " + preNDatabaseFile);
-                renameToBakFile(preNDatabaseFile);
+                Slog.i(TAG, "Migration complete - removing pre-N db " + preNDatabaseFile);
+                if (!SQLiteDatabase.deleteDatabase(preNDatabaseFile)) {
+                    Slog.e(TAG, "Cannot remove pre-N db " + preNDatabaseFile);
+                }
             }
             return ceHelper;
         }
 
-        private static void renameToBakFile(File file) {
-            File bakFile = new File(file.getPath() + ".bak");
-            if (!file.renameTo(bakFile)) {
-                Log.e(TAG, "Cannot move file to " + bakFile);
-            }
-        }
-
         private static boolean migratePreNDbToCe(File oldDbFile, File ceDbFile) {
-            Log.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
+            Slog.i(TAG, "Moving pre-N DB " + oldDbFile + " to CE " + ceDbFile);
             try {
                 FileUtils.copyFileOrThrow(oldDbFile, ceDbFile);
             } catch (IOException e) {
-                Log.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
+                Slog.e(TAG, "Cannot copy file to " + ceDbFile + " from " + oldDbFile, e);
                 // Try to remove potentially damaged file if I/O error occurred
                 deleteDbFileWarnIfFailed(ceDbFile);
                 return false;
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 5b8d98c..b075279 100755
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -711,6 +711,8 @@
                         updateServiceForegroundLocked(r.app, true);
                     }
                     getServiceMap(r.userId).ensureNotStartingBackground(r);
+                    mAm.notifyPackageUse(r.serviceInfo.packageName,
+                                         PackageManager.NOTIFY_PACKAGE_USE_FOREGROUND_SERVICE);
                 } else {
                     if (r.isForeground) {
                         r.isForeground = false;
@@ -1756,7 +1758,8 @@
             synchronized (r.stats.getBatteryStats()) {
                 r.stats.startLaunchedLocked();
             }
-            mAm.notifyPackageUse(r.serviceInfo.packageName);
+            mAm.notifyPackageUse(r.serviceInfo.packageName,
+                                 PackageManager.NOTIFY_PACKAGE_USE_SERVICE);
             app.forceProcessStateUpTo(ActivityManager.PROCESS_STATE_SERVICE);
             app.thread.scheduleCreateService(r, r.serviceInfo,
                     mAm.compatibilityInfoForPackageLocked(r.serviceInfo.applicationInfo),
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index d7afc13..1e74f81 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -341,6 +341,7 @@
 import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
 import static com.android.server.am.ActivityStackSupervisor.ActivityContainer.FORCE_NEW_TASK_FLAGS;
 import static com.android.server.am.ActivityStackSupervisor.DEFER_RESUME;
 import static com.android.server.am.ActivityStackSupervisor.FORCE_FOCUS;
@@ -3350,10 +3351,10 @@
         return proc;
     }
 
-    void notifyPackageUse(String packageName) {
+    void notifyPackageUse(String packageName, int reason) {
         IPackageManager pm = AppGlobals.getPackageManager();
         try {
-            pm.notifyPackageUse(packageName);
+            pm.notifyPackageUse(packageName, reason);
         } catch (RemoteException e) {
         }
     }
@@ -3687,29 +3688,27 @@
                 Watchdog.getInstance().processStarted(app.processName, startResult.pid);
             }
 
-            if (DEBUG_PROCESSES) {
-                checkTime(startTime, "startProcess: building log message");
-                StringBuilder buf = mStringBuilder;
-                buf.setLength(0);
-                buf.append("Start proc ");
-                buf.append(startResult.pid);
-                buf.append(':');
-                buf.append(app.processName);
-                buf.append('/');
-                UserHandle.formatUid(buf, uid);
-                if (!isActivityProcess) {
-                    buf.append(" [");
-                    buf.append(entryPoint);
-                    buf.append("]");
-                }
-                buf.append(" for ");
-                buf.append(hostingType);
-                if (hostingNameStr != null) {
-                    buf.append(" ");
-                    buf.append(hostingNameStr);
-                }
-                Slog.i(TAG, buf.toString());
+            checkTime(startTime, "startProcess: building log message");
+            StringBuilder buf = mStringBuilder;
+            buf.setLength(0);
+            buf.append("Start proc ");
+            buf.append(startResult.pid);
+            buf.append(':');
+            buf.append(app.processName);
+            buf.append('/');
+            UserHandle.formatUid(buf, uid);
+            if (!isActivityProcess) {
+                buf.append(" [");
+                buf.append(entryPoint);
+                buf.append("]");
             }
+            buf.append(" for ");
+            buf.append(hostingType);
+            if (hostingNameStr != null) {
+                buf.append(" ");
+                buf.append(hostingNameStr);
+            }
+            Slog.i(TAG, buf.toString());
             app.setPid(startResult.pid);
             app.usingWrapper = startResult.usingWrapper;
             app.removed = false;
@@ -6363,11 +6362,9 @@
                                 || (mBackupTarget.backupMode == BackupRecord.BACKUP_FULL));
             }
 
-            notifyPackageUse(app.instrumentationInfo != null
-                    ? app.instrumentationInfo.packageName
-                    : app.info.packageName);
             if (app.instrumentationClass != null) {
-                notifyPackageUse(app.instrumentationClass.getPackageName());
+                notifyPackageUse(app.instrumentationClass.getPackageName(),
+                                 PackageManager.NOTIFY_PACKAGE_USE_INSTRUMENTATION);
             }
             if (DEBUG_CONFIGURATION) Slog.v(TAG_CONFIGURATION, "Binding proc "
                     + processName + " with config " + mConfiguration);
@@ -6447,7 +6444,8 @@
         if (!badApp && mBackupTarget != null && mBackupTarget.appInfo.uid == app.uid) {
             if (DEBUG_BACKUP) Slog.v(TAG_BACKUP,
                     "New app is backup target, launching agent for " + app);
-            notifyPackageUse(mBackupTarget.appInfo.packageName);
+            notifyPackageUse(mBackupTarget.appInfo.packageName,
+                             PackageManager.NOTIFY_PACKAGE_USE_BACKUP);
             try {
                 thread.scheduleCreateBackupAgent(mBackupTarget.appInfo,
                         compatibilityInfoForPackageLocked(mBackupTarget.appInfo),
@@ -9613,8 +9611,13 @@
                     mWindowManager.setDockedStackCreateState(DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT,
                             null /* initialBounds */);
                 }
-                mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop, !FORCE_FOCUS,
-                        "moveTaskToStack", ANIMATE);
+                boolean result = mStackSupervisor.moveTaskToStackLocked(taskId, stackId, toTop,
+                        !FORCE_FOCUS, "moveTaskToStack", ANIMATE);
+                if (result && stackId == DOCKED_STACK_ID) {
+                    // If task moved to docked stack - show recents if needed.
+                    mStackSupervisor.moveHomeStackTaskToTop(RECENTS_ACTIVITY_TYPE,
+                            "moveTaskToDockedStack");
+                }
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
@@ -10094,7 +10097,8 @@
                     app.addPackage(cpi.applicationInfo.packageName, cpi.applicationInfo.versionCode,
                             mProcessStats);
                 }
-                notifyPackageUse(cpi.applicationInfo.packageName);
+                notifyPackageUse(cpi.applicationInfo.packageName,
+                                 PackageManager.NOTIFY_PACKAGE_USE_CONTENT_PROVIDER);
             }
         }
         return providers;
@@ -11502,6 +11506,19 @@
     }
 
     @Override
+    public void startConfirmDeviceCredentialIntent(Intent intent) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startConfirmDeviceCredentialIntent");
+        synchronized (this) {
+            final long ident = Binder.clearCallingIdentity();
+            try {
+                mActivityStarter.startConfirmCredentialIntent(intent);
+            } finally {
+                Binder.restoreCallingIdentity(ident);
+            }
+        }
+    }
+
+    @Override
     public void stopAppSwitches() {
         if (checkCallingPermission(android.Manifest.permission.STOP_APP_SWITCHES)
                 != PackageManager.PERMISSION_GRANTED) {
@@ -17156,9 +17173,9 @@
         if (isCallerSystem) {
             if (isProtectedBroadcast
                     || Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)
+                    || Intent.ACTION_DISMISS_KEYBOARD_SHORTCUTS.equals(action)
                     || Intent.ACTION_MEDIA_SCANNER_SCAN_FILE.equals(action)
-                    || Intent.ACTION_GET_PERMISSIONS_COUNT.equals(action)
-                    || Intent.ACTION_GET_PERMISSIONS_PACKAGES.equals(action)
+                    || Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(action)
                     || AppWidgetManager.ACTION_APPWIDGET_CONFIGURE.equals(action)
                     || AppWidgetManager.ACTION_APPWIDGET_UPDATE.equals(action)
                     || LocationManager.HIGH_POWER_REQUEST_CHANGE_ACTION.equals(action)) {
@@ -20040,7 +20057,7 @@
                         } else {
                             numEmpty++;
                             if (numEmpty > emptyProcessLimit) {
-                                app.kill("empty #" + numEmpty, DEBUG_PROCESSES);
+                                app.kill("empty #" + numEmpty, true);
                             }
                         }
                         break;
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index b043311..3df4a61 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -116,6 +116,7 @@
 import android.service.voice.IVoiceInteractionSession;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.Log;
 import android.util.Slog;
 import android.view.Display;
 
@@ -3431,8 +3432,10 @@
                 mWindowManager.prepareAppTransition(transit, false);
                 mWindowManager.setAppVisibility(r.appToken, false);
                 mWindowManager.executeAppTransition();
+                mStackSupervisor.mWaitingVisibleActivities.add(r);
             }
-            return finishCurrentActivityLocked(r, FINISH_AFTER_PAUSE, oomAdj) == null;
+            return finishCurrentActivityLocked(r, (r.visible || r.nowVisible) ?
+                    FINISH_AFTER_VISIBLE : FINISH_AFTER_PAUSE, oomAdj) == null;
         } else {
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Finish waiting for pause of: " + r);
         }
@@ -5023,10 +5026,20 @@
     }
 
     void positionTask(final TaskRecord task, int position) {
+        final ActivityRecord topRunningActivity = task.topRunningActivityLocked();
+        final boolean wasResumed = topRunningActivity == task.stack.mResumedActivity;
         final ActivityStack prevStack = preAddTask(task, "positionTask");
         task.stack = this;
         insertTaskAtPosition(task, position);
         postAddTask(task, prevStack);
+        if (wasResumed) {
+            if (mResumedActivity != null) {
+                Log.wtf(TAG, "mResumedActivity was already set when moving mResumedActivity from"
+                        + " other stack to this stack mResumedActivity=" + mResumedActivity
+                        + " other mResumedActivity=" + topRunningActivity);
+            }
+            mResumedActivity = topRunningActivity;
+        }
     }
 
     private ActivityStack preAddTask(TaskRecord task, String reason) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 97ee744..f281683 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -30,8 +30,6 @@
 import android.app.IActivityContainerCallback;
 import android.app.IActivityManager;
 import android.app.IActivityManager.WaitResult;
-import android.app.KeyguardManager;
-import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.app.ResultInfo;
 import android.app.StatusBarManager;
@@ -40,7 +38,6 @@
 import android.content.Context;
 import android.content.IIntentSender;
 import android.content.Intent;
-import android.content.IntentSender;
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
@@ -171,6 +168,7 @@
 import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
 import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
 import static com.android.server.am.ActivityStack.STACK_INVISIBLE;
+import static com.android.server.am.ActivityStack.STACK_VISIBLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
 import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
@@ -1215,7 +1213,8 @@
                 // Home process is the root process of the task.
                 mService.mHomeProcess = task.mActivities.get(0).app;
             }
-            mService.notifyPackageUse(r.intent.getComponent().getPackageName());
+            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
+                                      PackageManager.NOTIFY_PACKAGE_USE_ACTIVITY);
             r.sleeping = false;
             r.forceNewConfig = false;
             mService.showAskCompatModeDialogLocked(r);
@@ -3399,6 +3398,7 @@
         info.displayId = Display.DEFAULT_DISPLAY;
         info.stackId = stack.mStackId;
         info.userId = stack.mCurrentUser;
+        info.visible = stack.getStackVisibilityLocked(null) == STACK_VISIBLE;
 
         ArrayList<TaskRecord> tasks = stack.getAllTasks();
         final int numTasks = tasks.size();
@@ -3421,6 +3421,9 @@
         info.taskNames = taskNames;
         info.taskBounds = taskBounds;
         info.taskUserIds = taskUserIds;
+
+        final ActivityRecord top = stack.topRunningActivityLocked();
+        info.topActivity = top != null ? top.intent.getComponent() : null;
         return info;
     }
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 9c93f2c..6622b34 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -33,6 +33,7 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
@@ -526,8 +527,13 @@
 
         doPendingActivityLaunchesLocked(false);
 
-        err = startActivityUnchecked(
-                r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
+        try {
+            mService.mWindowManager.deferSurfaceLayout();
+            err = startActivityUnchecked(r, sourceRecord, voiceSession, voiceInteractor, startFlags,
+                    true, options, inTask);
+        } finally {
+            mService.mWindowManager.continueSurfaceLayout();
+        }
         postStartActivityUncheckedProcessing(r, err, stack.mStackId);
         return err;
     }
@@ -582,7 +588,7 @@
                 null /*voiceInteractor*/, null /*resultTo*/, null /*resultWho*/,
                 0 /*requestCode*/, 0 /*callingPid*/, 0 /*callingUid*/, null /*callingPackage*/,
                 0 /*realCallingPid*/, 0 /*realCallingUid*/, 0 /*startFlags*/, null /*options*/,
-                false /*ignoreTargetSecurity*/, false /*componentSpecified*/,  null /*outActivity*/,
+                false /*ignoreTargetSecurity*/, false /*componentSpecified*/, null /*outActivity*/,
                 null /*container*/, null /*inTask*/);
         if (mSupervisor.inResumeTopActivity) {
             // If we are in resume section already, home activity will be initialized, but not
@@ -612,11 +618,6 @@
                 .getSystemService(Context.KEYGUARD_SERVICE);
         final Intent credential =
                 km.createConfirmDeviceCredentialIntent(null, null, userId);
-        credential.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
-                Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
-                Intent.FLAG_ACTIVITY_TASK_ON_HOME);
-        final ActivityOptions options = ActivityOptions.makeBasic();
-        options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
         final ActivityRecord activityRecord = targetStack.topRunningActivityLocked();
         if (activityRecord != null) {
             final IIntentSender target = mService.getIntentSenderLocked(
@@ -633,11 +634,19 @@
                     null);
             credential.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
             // Show confirm credentials activity.
-            mService.mContext.startActivityAsUser(credential, options.toBundle(),
-                    UserHandle.CURRENT);
+            startConfirmCredentialIntent(credential);
         }
     }
 
+    void startConfirmCredentialIntent(Intent intent) {
+        intent.addFlags(FLAG_ACTIVITY_NEW_TASK |
+                FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS |
+                FLAG_ACTIVITY_TASK_ON_HOME);
+        final ActivityOptions options = ActivityOptions.makeBasic();
+        options.setLaunchTaskId(mSupervisor.getHomeActivity().task.taskId);
+        mService.mContext.startActivityAsUser(intent, options.toBundle(),
+                UserHandle.CURRENT);
+    }
 
     final int startActivityMayWait(IApplicationThread caller, int callingUid,
             String callingPackage, Intent intent, String resolvedType,
@@ -1432,7 +1441,7 @@
                             == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
                 if (!willClearTask) {
                     final ActivityStack launchStack = getLaunchStack(
-                            mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, true);
+                            mStartActivity, mLaunchFlags, mStartActivity.task, mOptions);
                     if (launchStack == null || launchStack == mTargetStack) {
                         // We only want to move to the front, if we aren't going to launch on a
                         // different stack. If we launch on a different stack, we will put the
@@ -1606,8 +1615,11 @@
         // We only want to allow changing stack if the target task is not the top one,
         // otherwise we would move the launching task to the other side, rather than show
         // two side by side.
-        final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
-        mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+        final boolean moveStackAllowed = sourceTask.stack.topTask() != sourceTask;
+        if (moveStackAllowed) {
+            mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+                    mOptions);
+        }
 
         if (mTargetStack == null) {
             mTargetStack = sourceTask.stack;
@@ -1780,7 +1792,7 @@
             return mSupervisor.mHomeStack;
         }
 
-        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
+        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions);
         if (stack != null) {
             return stack;
         }
@@ -1845,7 +1857,13 @@
     }
 
     private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
-            ActivityOptions aOptions, boolean launchToSideAllowed) {
+            ActivityOptions aOptions) {
+
+        // We are reusing a task, keep the stack!
+        if (mReuseTask != null) {
+            return mReuseTask.stack;
+        }
+
         final int launchStackId =
                 (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
 
@@ -1857,7 +1875,7 @@
             return mSupervisor.getStack(FULLSCREEN_WORKSPACE_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
         }
 
-        if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
+        if ((launchFlags & FLAG_ACTIVITY_LAUNCH_ADJACENT) == 0) {
             return null;
         }
         // Otherwise handle adjacent launch.
diff --git a/services/core/java/com/android/server/am/AppErrors.java b/services/core/java/com/android/server/am/AppErrors.java
index 68bd2fd..e9ed34b 100644
--- a/services/core/java/com/android/server/am/AppErrors.java
+++ b/services/core/java/com/android/server/am/AppErrors.java
@@ -293,19 +293,7 @@
             return;
         }
 
-        if (proc.thread != null) {
-            if (proc.pid == Process.myPid()) {
-                Log.w(TAG, "crashApplication: trying to crash self!");
-                return;
-            }
-            long ident = Binder.clearCallingIdentity();
-            try {
-                proc.thread.scheduleCrash(message);
-            } catch (RemoteException e) {
-            } finally {
-                Binder.restoreCallingIdentity(ident);
-            }
-        }
+        proc.scheduleCrash(message);
     }
 
     /**
diff --git a/services/core/java/com/android/server/am/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index 37c7765..1222f54 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -38,6 +38,7 @@
 import android.content.pm.ResolveInfo;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.DeadObjectException;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
@@ -273,7 +274,8 @@
             if (DEBUG_BROADCAST_LIGHT) Slog.v(TAG_BROADCAST,
                     "Delivering to component " + r.curComponent
                     + ": " + r);
-            mService.notifyPackageUse(r.intent.getComponent().getPackageName());
+            mService.notifyPackageUse(r.intent.getComponent().getPackageName(),
+                                      PackageManager.NOTIFY_PACKAGE_USE_BROADCAST_RECEIVER);
             app.thread.scheduleReceiver(new Intent(r.intent), r.curReceiver,
                     mService.compatibilityInfoForPackageLocked(r.curReceiver.applicationInfo),
                     r.resultCode, r.resultData, r.resultExtras, r.ordered, r.userId,
@@ -446,7 +448,7 @@
         }
     }
 
-    private static void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
+    private void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
             Intent intent, int resultCode, String data, Bundle extras,
             boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
         // Send the intent to the receiver asynchronously using one-way binder calls.
@@ -454,8 +456,23 @@
             if (app.thread != null) {
                 // If we have an app thread, do the call through that so it is
                 // correctly ordered with other one-way calls.
-                app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
-                        data, extras, ordered, sticky, sendingUser, app.repProcState);
+                try {
+                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
+                            data, extras, ordered, sticky, sendingUser, app.repProcState);
+                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
+                // DeadObjectException when the process isn't actually dead.
+                //} catch (DeadObjectException ex) {
+                // Failed to call into the process.  It's dying so just let it die and move on.
+                //    throw ex;
+                } catch (RemoteException ex) {
+                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
+                    synchronized (mService) {
+                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName
+                                + " (pid " + app.pid + "). Crashing it.");
+                        app.scheduleCrash("can't deliver broadcast");
+                    }
+                    throw ex;
+                }
             } else {
                 // Application has died. Receiver doesn't exist.
                 throw new RemoteException("app.thread must not be null");
@@ -853,6 +870,7 @@
                             Slog.w(TAG, "Failure ["
                                     + mQueueName + "] sending broadcast result of "
                                     + r.intent, e);
+
                         }
                     }
 
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 93d4060..059acbd 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -37,9 +37,11 @@
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.res.CompatibilityInfo;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.Trace;
 import android.os.UserHandle;
@@ -552,6 +554,29 @@
         return adj;
     }
 
+    void scheduleCrash(String message) {
+        // Checking killedbyAm should keep it from showing the crash dialog if the process
+        // was already dead for a good / normal reason.
+        if (!killedByAm) {
+            if (thread != null) {
+                if (pid == Process.myPid()) {
+                    Slog.w(TAG, "scheduleCrash: trying to crash system process!");
+                    return;
+                }
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    thread.scheduleCrash(message);
+                } catch (RemoteException e) {
+                    // If it's already dead our work is done. If it's wedged just kill it.
+                    // We won't get the crash dialog or the error reporting.
+                    kill("scheduleCrash for '" + message + "' failed", true);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+            }
+        }
+    }
+
     void kill(String reason, boolean noisy) {
         if (!killedByAm) {
             Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
diff --git a/services/core/java/com/android/server/am/TaskPersister.java b/services/core/java/com/android/server/am/TaskPersister.java
index a2472ac..48fecd5 100644
--- a/services/core/java/com/android/server/am/TaskPersister.java
+++ b/services/core/java/com/android/server/am/TaskPersister.java
@@ -17,8 +17,6 @@
 package com.android.server.am;
 
 import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.ActivityManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.os.Debug;
@@ -519,7 +517,7 @@
         if (DEBUG) Slog.d(TAG, "removeObsoleteFiles: persistentTaskIds=" + persistentTaskIds +
                 " files=" + files);
         if (files == null) {
-            Slog.e(TAG, "File error accessing recents directory (too many files open?).");
+            Slog.e(TAG, "File error accessing recents directory (directory doesn't exist?).");
             return;
         }
         for (int fileNdx = 0; fileNdx < files.length; ++fileNdx) {
@@ -597,15 +595,12 @@
     }
 
     static File getUserImagesDir(int userId) {
-        File userImagesDir = new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
+        return new File(Environment.getDataSystemCeDirectory(userId), IMAGES_DIRNAME);
+    }
 
-        if (!userImagesDir.exists()) {
-            if (!userImagesDir.mkdir()) {
-                Slog.e(TAG, "Failure creating images directory for user " + userId + ": "
-                        + userImagesDir);
-            }
-        }
-        return userImagesDir;
+    private static boolean createParentDirectory(String filePath) {
+        File parentDir = new File(filePath).getParentFile();
+        return parentDir.exists() || parentDir.mkdirs();
     }
 
     private class LazyTaskWriterThread extends Thread {
@@ -693,6 +688,10 @@
                 if (item instanceof ImageWriteQueueItem) {
                     ImageWriteQueueItem imageWriteQueueItem = (ImageWriteQueueItem) item;
                     final String filePath = imageWriteQueueItem.mFilePath;
+                    if (!createParentDirectory(filePath)) {
+                        Slog.e(TAG, "Error while creating images directory for file: " + filePath);
+                        continue;
+                    }
                     final Bitmap bitmap = imageWriteQueueItem.mImage;
                     if (DEBUG) Slog.d(TAG, "writing bitmap: filename=" + filePath);
                     FileOutputStream imageFile = null;
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index d330756..f7784ac 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -34,10 +34,11 @@
 import android.net.ProxyInfo;
 import android.net.TrafficStats;
 import android.net.Uri;
-import android.net.metrics.CaptivePortalCheckResultEvent;
-import android.net.metrics.CaptivePortalStateChangeEvent;
+import android.net.metrics.ValidationProbeEvent;
+import android.net.metrics.NetworkEvent;
 import android.net.wifi.WifiInfo;
 import android.net.wifi.WifiManager;
+import android.net.util.Stopwatch;
 import android.os.Handler;
 import android.os.Message;
 import android.os.Process;
@@ -79,7 +80,7 @@
  */
 public class NetworkMonitor extends StateMachine {
     private static final boolean DBG = false;
-    private static final String TAG = "NetworkMonitor";
+    private static final String TAG = NetworkMonitor.class.getSimpleName();
     private static final String DEFAULT_SERVER = "connectivitycheck.gstatic.com";
     private static final int SOCKET_TIMEOUT_MS = 10000;
     public static final String ACTION_NETWORK_CONDITIONS_MEASURED =
@@ -221,6 +222,7 @@
     private final Context mContext;
     private final Handler mConnectivityServiceHandler;
     private final NetworkAgentInfo mNetworkAgentInfo;
+    private final int mNetId;
     private final TelephonyManager mTelephonyManager;
     private final WifiManager mWifiManager;
     private final AlarmManager mAlarmManager;
@@ -246,6 +248,8 @@
 
     private final LocalLog validationLogs = new LocalLog(20); // 20 lines
 
+    private final Stopwatch mEvaluationTimer = new Stopwatch();
+
     public NetworkMonitor(Context context, Handler handler, NetworkAgentInfo networkAgentInfo,
             NetworkRequest defaultRequest) {
         // Add suffix indicating which NetworkMonitor we're talking about.
@@ -254,6 +258,7 @@
         mContext = context;
         mConnectivityServiceHandler = handler;
         mNetworkAgentInfo = networkAgentInfo;
+        mNetId = mNetworkAgentInfo.network.netId;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mWifiManager = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
         mAlarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
@@ -300,13 +305,11 @@
                     transitionTo(mLingeringState);
                     return HANDLED;
                 case CMD_NETWORK_CONNECTED:
-                    CaptivePortalStateChangeEvent.logEvent(
-                            CaptivePortalStateChangeEvent.NETWORK_MONITOR_CONNECTED);
+                    NetworkEvent.logEvent(mNetId, NetworkEvent.NETWORK_CONNECTED);
                     transitionTo(mEvaluatingState);
                     return HANDLED;
                 case CMD_NETWORK_DISCONNECTED:
-                    CaptivePortalStateChangeEvent.logEvent(
-                            CaptivePortalStateChangeEvent.NETWORK_MONITOR_DISCONNECTED);
+                    NetworkEvent.logEvent(mNetId, NetworkEvent.NETWORK_DISCONNECTED);
                     if (mLaunchCaptivePortalAppBroadcastReceiver != null) {
                         mContext.unregisterReceiver(mLaunchCaptivePortalAppBroadcastReceiver);
                         mLaunchCaptivePortalAppBroadcastReceiver = null;
@@ -336,7 +339,7 @@
                             mUserDoesNotWant = true;
                             mConnectivityServiceHandler.sendMessage(obtainMessage(
                                     EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
-                                    mNetworkAgentInfo.network.netId, null));
+                                    mNetId, null));
                             // TODO: Should teardown network.
                             mUidResponsibleForReeval = 0;
                             transitionTo(mEvaluatingState);
@@ -356,8 +359,10 @@
     private class ValidatedState extends State {
         @Override
         public void enter() {
-            CaptivePortalStateChangeEvent.logEvent(
-                   CaptivePortalStateChangeEvent.NETWORK_MONITOR_VALIDATED);
+            if (mEvaluationTimer.isRunning()) {
+                NetworkEvent.logValidated(mNetId, mEvaluationTimer.stop());
+                mEvaluationTimer.reset();
+            }
             mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
                     NETWORK_TEST_RESULT_VALID, mNetworkAgentInfo.network.netId, null));
         }
@@ -436,6 +441,12 @@
 
         @Override
         public void enter() {
+            // If we have already started to track time spent in EvaluatingState
+            // don't reset the timer due simply to, say, commands or events that
+            // cause us to exit and re-enter EvaluatingState.
+            if (!mEvaluationTimer.isStarted()) {
+                mEvaluationTimer.start();
+            }
             sendMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
             if (mUidResponsibleForReeval != INVALID_UID) {
                 TrafficStats.setThreadStatsUid(mUidResponsibleForReeval);
@@ -481,22 +492,20 @@
                     // will be unresponsive. isCaptivePortal() could be executed on another Thread
                     // if this is found to cause problems.
                     CaptivePortalProbeResult probeResult = isCaptivePortal();
-                    CaptivePortalCheckResultEvent.logEvent(mNetworkAgentInfo.network.netId,
-                            probeResult.mHttpResponseCode);
                     if (probeResult.mHttpResponseCode == 204) {
                         transitionTo(mValidatedState);
                     } else if (probeResult.mHttpResponseCode >= 200 &&
                             probeResult.mHttpResponseCode <= 399) {
                         mConnectivityServiceHandler.sendMessage(obtainMessage(EVENT_NETWORK_TESTED,
-                                NETWORK_TEST_RESULT_INVALID, mNetworkAgentInfo.network.netId,
-                                probeResult.mRedirectUrl));
+                                NETWORK_TEST_RESULT_INVALID, mNetId, probeResult.mRedirectUrl));
                         transitionTo(mCaptivePortalState);
                     } else {
                         final Message msg = obtainMessage(CMD_REEVALUATE, ++mReevaluateToken, 0);
                         sendMessageDelayed(msg, mReevaluateDelayMs);
+                        NetworkEvent.logEvent(mNetId, NetworkEvent.NETWORK_VALIDATION_FAILED);
                         mConnectivityServiceHandler.sendMessage(obtainMessage(
-                                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID,
-                                mNetworkAgentInfo.network.netId, probeResult.mRedirectUrl));
+                                EVENT_NETWORK_TESTED, NETWORK_TEST_RESULT_INVALID, mNetId,
+                                probeResult.mRedirectUrl));
                         if (mAttempts >= BLAME_FOR_EVALUATION_ATTEMPTS) {
                             // Don't continue to blame UID forever.
                             TrafficStats.clearThreadStatsUid();
@@ -511,7 +520,7 @@
                     // Before IGNORE_REEVALUATE_ATTEMPTS attempts are made,
                     // ignore any re-evaluation requests. After, restart the
                     // evaluation process via EvaluatingState#enter.
-                    return mAttempts < IGNORE_REEVALUATE_ATTEMPTS ? HANDLED : NOT_HANDLED;
+                    return (mAttempts < IGNORE_REEVALUATE_ATTEMPTS) ? HANDLED : NOT_HANDLED;
                 default:
                     return NOT_HANDLED;
             }
@@ -553,6 +562,10 @@
 
         @Override
         public void enter() {
+            if (mEvaluationTimer.isRunning()) {
+                NetworkEvent.logCaptivePortalFound(mNetId, mEvaluationTimer.stop());
+                mEvaluationTimer.reset();
+            }
             // Don't annoy user with sign-in notifications.
             if (mDontDisplaySigninNotification) return;
             // Create a CustomIntentReceiver that sends us a
@@ -593,7 +606,8 @@
 
         @Override
         public void enter() {
-            final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetworkAgentInfo.network.netId;
+            mEvaluationTimer.reset();
+            final String cmdName = ACTION_LINGER_EXPIRED + "." + mNetId;
             mWakeupMessage = makeWakeupMessage(mContext, getHandler(), cmdName, CMD_LINGER_EXPIRED);
             long wakeupTime = SystemClock.elapsedRealtime() + mLingerDelayMs;
             mWakeupMessage.schedule(wakeupTime);
@@ -663,6 +677,7 @@
         HttpURLConnection urlConnection = null;
         int httpResponseCode = 599;
         String redirectUrl = null;
+        final Stopwatch probeTimer = new Stopwatch().start();
         try {
             URL url = new URL(getCaptivePortalServerUrl(mContext));
             // On networks with a PAC instead of fetching a URL that should result in a 204
@@ -759,6 +774,8 @@
                 urlConnection.disconnect();
             }
         }
+        final int probeType = ValidationProbeEvent.PROBE_HTTP;
+        ValidationProbeEvent.logEvent(mNetId, probeTimer.stop(), probeType, httpResponseCode);
         return new CaptivePortalProbeResult(httpResponseCode, redirectUrl);
     }
 
diff --git a/services/core/java/com/android/server/connectivity/Tethering.java b/services/core/java/com/android/server/connectivity/Tethering.java
index 79b5978..c2022d5 100644
--- a/services/core/java/com/android/server/connectivity/Tethering.java
+++ b/services/core/java/com/android/server/connectivity/Tethering.java
@@ -273,9 +273,6 @@
                     // ignore usb0 down after enabling RNDIS
                     // we will handle disconnect in interfaceRemoved instead
                     if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
-                } else if (isWifi(iface)) {
-                    // handle disconnect in interfaceRemoved
-                    if (VDBG) Log.d(TAG, "ignore interface down for " + iface);
                 } else if (sm != null) {
                     sm.sendMessage(TetherInterfaceSM.CMD_INTERFACE_DOWN);
                     mIfaces.remove(iface);
diff --git a/services/core/java/com/android/server/display/AutomaticBrightnessController.java b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
index 5c80d04..c16dac2 100644
--- a/services/core/java/com/android/server/display/AutomaticBrightnessController.java
+++ b/services/core/java/com/android/server/display/AutomaticBrightnessController.java
@@ -147,6 +147,9 @@
     // A ring buffer containing all of the recent ambient light sensor readings.
     private AmbientLightRingBuffer mAmbientLightRingBuffer;
 
+    // A ring buffer containing the light sensor readings for the initial horizon period.
+    private AmbientLightRingBuffer mInitialHorizonAmbientLightRingBuffer;
+
     // The handler
     private AutomaticBrightnessHandler mHandler;
 
@@ -204,7 +207,10 @@
         mScreenAutoBrightnessAdjustmentMaxGamma = autoBrightnessAdjustmentMaxGamma;
 
         mHandler = new AutomaticBrightnessHandler(looper);
-        mAmbientLightRingBuffer = new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
+        mAmbientLightRingBuffer =
+            new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
+        mInitialHorizonAmbientLightRingBuffer =
+            new AmbientLightRingBuffer(mLightSensorRate, mAmbientLightHorizon);
 
         if (!DEBUG_PRETEND_LIGHT_SENSOR_ABSENT) {
             mLightSensor = mSensorManager.getDefaultSensor(Sensor.TYPE_LIGHT);
@@ -273,6 +279,8 @@
         pw.println("  mLastObservedLuxTime=" + TimeUtils.formatUptime(mLastObservedLuxTime));
         pw.println("  mRecentLightSamples=" + mRecentLightSamples);
         pw.println("  mAmbientLightRingBuffer=" + mAmbientLightRingBuffer);
+        pw.println("  mInitialHorizonAmbientLightRingBuffer=" +
+                mInitialHorizonAmbientLightRingBuffer);
         pw.println("  mScreenAutoBrightness=" + mScreenAutoBrightness);
         pw.println("  mScreenAutoBrightnessAdjustment=" + mScreenAutoBrightnessAdjustment);
         pw.println("  mScreenAutoBrightnessAdjustmentMaxGamma=" + mScreenAutoBrightnessAdjustmentMaxGamma);
@@ -295,6 +303,7 @@
                 mAmbientLuxValid = !mResetAmbientLuxAfterWarmUpConfig;
                 mRecentLightSamples = 0;
                 mAmbientLightRingBuffer.clear();
+                mInitialHorizonAmbientLightRingBuffer.clear();
                 mHandler.removeMessages(MSG_UPDATE_AMBIENT_LUX);
                 mSensorManager.unregisterListener(mLightSensorListener);
             }
@@ -311,6 +320,11 @@
 
     private void applyLightSensorMeasurement(long time, float lux) {
         mRecentLightSamples++;
+        // Store all of the light measurements for the intial horizon period. This is to help
+        // diagnose dim wake ups and slow responses in b/27951906.
+        if (time <= mLightSensorEnableTime + mAmbientLightHorizon) {
+            mInitialHorizonAmbientLightRingBuffer.push(time, lux);
+        }
         mAmbientLightRingBuffer.prune(time - mAmbientLightHorizon);
         mAmbientLightRingBuffer.push(time, lux);
 
@@ -617,7 +631,7 @@
         void updateBrightness();
     }
 
-    private static final class AmbientLightRingBuffer{
+    private static final class AmbientLightRingBuffer {
         // Proportional extra capacity of the buffer beyond the expected number of light samples
         // in the horizon
         private static final float BUFFER_SLACK = 1.5f;
diff --git a/services/core/java/com/android/server/fingerprint/ClientMonitor.java b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
index 45b6d3e..8163b79 100644
--- a/services/core/java/com/android/server/fingerprint/ClientMonitor.java
+++ b/services/core/java/com/android/server/fingerprint/ClientMonitor.java
@@ -38,7 +38,7 @@
     protected static final boolean DEBUG = FingerprintService.DEBUG;
     private IBinder mToken;
     private IFingerprintServiceReceiver mReceiver;
-    private int mCallingUserId;
+    private int mTargetUserId;
     private int mGroupId;
     private boolean mIsRestricted; // True if client does not have MANAGE_FINGERPRINT permission
     private String mOwner;
@@ -50,20 +50,20 @@
      * @param halDeviceId the HAL device ID of the associated fingerprint hardware
      * @param token a unique token for the client
      * @param receiver recipient of related events (e.g. authentication)
-     * @param callingUserId user id of calling user
+     * @param userId target user id for operation
      * @param groupId groupId for the fingerprint set
      * @param restricted whether or not client has the {@link Manifest#MANAGE_FINGERPRINT}
      * permission
      * @param owner name of the client that owns this
      */
     public ClientMonitor(Context context, long halDeviceId, IBinder token,
-            IFingerprintServiceReceiver receiver, int callingUserId, int groupId,boolean restricted,
+            IFingerprintServiceReceiver receiver, int userId, int groupId,boolean restricted,
             String owner) {
         mContext = context;
         mHalDeviceId = halDeviceId;
         mToken = token;
         mReceiver = receiver;
-        mCallingUserId = callingUserId;
+        mTargetUserId = userId;
         mGroupId = groupId;
         mIsRestricted = restricted;
         mOwner = owner;
@@ -197,8 +197,8 @@
         return mIsRestricted;
     }
 
-    public final int getCallingUserId() {
-        return mCallingUserId;
+    public final int getTargetUserId() {
+        return mTargetUserId;
     }
 
     public final int getGroupId() {
diff --git a/services/core/java/com/android/server/fingerprint/EnumerateClient.java b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
index e826fee..52dbd5d 100644
--- a/services/core/java/com/android/server/fingerprint/EnumerateClient.java
+++ b/services/core/java/com/android/server/fingerprint/EnumerateClient.java
@@ -41,7 +41,7 @@
         try {
             final int result = daemon.enumerate();
             if (result != 0) {
-                Slog.w(TAG, "start enumerate for user " + getCallingUserId()
+                Slog.w(TAG, "start enumerate for user " + getTargetUserId()
                     + " failed, result=" + result);
                 onError(FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
                 return result;
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index fcf7bf5..9a2db8e 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -356,7 +356,7 @@
         }
     }
 
-    void startRemove(IBinder token, int fingerId, int callingUserId, int groupId,
+    void startRemove(IBinder token, int fingerId, int groupId, int userId,
             IFingerprintServiceReceiver receiver, boolean restricted) {
         IFingerprintDaemon daemon = getFingerprintDaemon();
         if (daemon == null) {
@@ -364,7 +364,7 @@
             return;
         }
         RemovalClient client = new RemovalClient(getContext(), mHalDeviceId, token,
-                receiver, callingUserId, groupId, fingerId, restricted, token.toString()) {
+                receiver, fingerId, groupId, userId, restricted, token.toString()) {
             @Override
             public void notifyUserActivity() {
                 FingerprintService.this.userActivity();
@@ -794,14 +794,13 @@
 
         @Override // Binder call
         public void remove(final IBinder token, final int fingerId, final int groupId,
-                final IFingerprintServiceReceiver receiver) {
+                final int userId, final IFingerprintServiceReceiver receiver) {
             checkPermission(MANAGE_FINGERPRINT); // TODO: Maybe have another permission
             final boolean restricted = isRestricted();
-            final int callingUserId = UserHandle.getCallingUserId();
             mHandler.post(new Runnable() {
                 @Override
                 public void run() {
-                    startRemove(token, fingerId, callingUserId, groupId, receiver, restricted);
+                    startRemove(token, fingerId, groupId, userId, receiver, restricted);
                 }
             });
 
diff --git a/services/core/java/com/android/server/fingerprint/RemovalClient.java b/services/core/java/com/android/server/fingerprint/RemovalClient.java
index ffa3c3f..bcf2264 100644
--- a/services/core/java/com/android/server/fingerprint/RemovalClient.java
+++ b/services/core/java/com/android/server/fingerprint/RemovalClient.java
@@ -30,14 +30,12 @@
  */
 public abstract class RemovalClient extends ClientMonitor {
     private int mFingerId;
-    private int mUserIdForRemove;
 
     public RemovalClient(Context context, long halDeviceId, IBinder token,
-            IFingerprintServiceReceiver receiver, int userId, int groupId, int fingerId,
+            IFingerprintServiceReceiver receiver, int fingerId, int groupId, int userId,
             boolean restricted, String owner) {
         super(context, halDeviceId, token, receiver, userId, groupId, restricted, owner);
         mFingerId = fingerId;
-        mUserIdForRemove = userId;
     }
 
     @Override
@@ -72,25 +70,21 @@
      */
     private boolean sendRemoved(int fingerId, int groupId) {
         IFingerprintServiceReceiver receiver = getReceiver();
-        if (receiver == null)
-            return true; // client not listening
         try {
-            receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
-            return fingerId == 0;
+            if (receiver != null) {
+                receiver.onRemoved(getHalDeviceId(), fingerId, groupId);
+            }
         } catch (RemoteException e) {
             Slog.w(TAG, "Failed to notify Removed:", e);
         }
-        return false;
+        return fingerId == 0;
     }
 
     @Override
     public boolean onRemoved(int fingerId, int groupId) {
         if (fingerId != 0) {
-            if (fingerId != mFingerId)
             FingerprintUtils.getInstance().removeFingerprintIdForUser(getContext(), fingerId,
-                    mUserIdForRemove);
-        } else {
-            mUserIdForRemove = UserHandle.USER_NULL;
+                    getTargetUserId());
         }
         return sendRemoved(fingerId, getGroupId());
     }
diff --git a/services/core/java/com/android/server/input/InputManagerService.java b/services/core/java/com/android/server/input/InputManagerService.java
index c7c765bb..c649012 100644
--- a/services/core/java/com/android/server/input/InputManagerService.java
+++ b/services/core/java/com/android/server/input/InputManagerService.java
@@ -1349,8 +1349,8 @@
         if (keyboardLayoutDescriptor == null) {
             throw new IllegalArgumentException("keyboardLayoutDescriptor must not be null");
         }
-        if (imeInfo == null || imeSubtype == null) {
-            throw new IllegalArgumentException("imeInfo and imeSubtype must not be null");
+        if (imeInfo == null) {
+            throw new IllegalArgumentException("imeInfo must not be null");
         }
         InputMethodSubtypeHandle handle = new InputMethodSubtypeHandle(imeInfo, imeSubtype);
         setKeyboardLayoutForInputDeviceInner(identifier, handle, keyboardLayoutDescriptor);
diff --git a/services/core/java/com/android/server/notification/CalendarTracker.java b/services/core/java/com/android/server/notification/CalendarTracker.java
index 783b16f..5d50f3b 100644
--- a/services/core/java/com/android/server/notification/CalendarTracker.java
+++ b/services/core/java/com/android/server/notification/CalendarTracker.java
@@ -43,14 +43,15 @@
     private static final int EVENT_CHECK_LOOKAHEAD = 24 * 60 * 60 * 1000;
 
     private static final String[] INSTANCE_PROJECTION = {
-        Instances.BEGIN,
-        Instances.END,
-        Instances.TITLE,
-        Instances.VISIBLE,
-        Instances.EVENT_ID,
-        Instances.OWNER_ACCOUNT,
-        Instances.CALENDAR_ID,
-        Instances.AVAILABILITY,
+            Instances.BEGIN,
+            Instances.END,
+            Instances.TITLE,
+            Instances.VISIBLE,
+            Instances.EVENT_ID,
+            Instances.CALENDAR_DISPLAY_NAME,
+            Instances.OWNER_ACCOUNT,
+            Instances.CALENDAR_ID,
+            Instances.AVAILABILITY,
     };
 
     private static final String INSTANCE_ORDER_BY = Instances.BEGIN + " ASC";
@@ -87,49 +88,6 @@
         pw.print(prefix); pw.print("u="); pw.println(mUserContext.getUserId());
     }
 
-    public void dumpContent(Uri uri) {
-        Log.d(TAG, "dumpContent: " + uri);
-        final Cursor cursor = mUserContext.getContentResolver().query(uri, null, null, null, null);
-        try {
-            int r = 0;
-            while (cursor.moveToNext()) {
-                Log.d(TAG, "Row " + (++r) + ": id="
-                        + cursor.getInt(cursor.getColumnIndex(BaseColumns._ID)));
-                for (int i = 0; i < cursor.getColumnCount(); i++) {
-                    final String name = cursor.getColumnName(i);
-                    final int type = cursor.getType(i);
-                    Object o = null;
-                    String typeName = null;
-                    switch (type) {
-                        case Cursor.FIELD_TYPE_INTEGER:
-                            o = cursor.getLong(i);
-                            typeName = "INTEGER";
-                            break;
-                        case Cursor.FIELD_TYPE_STRING:
-                            o = cursor.getString(i);
-                            typeName = "STRING";
-                            break;
-                        case Cursor.FIELD_TYPE_NULL:
-                            o = null;
-                            typeName = "NULL";
-                            break;
-                        default:
-                            throw new UnsupportedOperationException("type: " + type);
-                    }
-                    if (name.equals(BaseColumns._ID)
-                            || name.toLowerCase().contains("sync")
-                            || o == null) {
-                        continue;
-                    }
-                    Log.d(TAG, "  " + name + "(" + typeName + ")=" + o);
-                }
-            }
-            Log.d(TAG, "  " + uri + " " + r + " rows");
-        } finally {
-            cursor.close();
-        }
-    }
-
     private ArraySet<Long> getPrimaryCalendars() {
         final long start = System.currentTimeMillis();
         final ArraySet<Long> rt = new ArraySet<>();
@@ -170,18 +128,21 @@
                 final String title = cursor.getString(2);
                 final boolean calendarVisible = cursor.getInt(3) == 1;
                 final int eventId = cursor.getInt(4);
-                final String owner = cursor.getString(5);
-                final long calendarId = cursor.getLong(6);
-                final int availability = cursor.getInt(7);
+                final String name = cursor.getString(5);
+                final String owner = cursor.getString(6);
+                final long calendarId = cursor.getLong(7);
+                final int availability = cursor.getInt(8);
                 final boolean calendarPrimary = primaryCalendars.contains(calendarId);
-                if (DEBUG) Log.d(TAG, String.format("%s %s-%s v=%s a=%s eid=%s o=%s cid=%s p=%s",
+                if (DEBUG) Log.d(TAG, String.format(
+                        "%s %s-%s v=%s a=%s eid=%s n=%s o=%s cid=%s p=%s",
                         title,
                         new Date(begin), new Date(end), calendarVisible,
-                        availabilityToString(availability), eventId, owner, calendarId,
+                        availabilityToString(availability), eventId, name, owner, calendarId,
                         calendarPrimary));
                 final boolean meetsTime = time >= begin && time < end;
                 final boolean meetsCalendar = calendarVisible && calendarPrimary
-                        && (filter.calendar == null || Objects.equals(filter.calendar, owner));
+                        && (filter.calendar == null || Objects.equals(filter.calendar, owner)
+                        || Objects.equals(filter.calendar, name));
                 final boolean meetsAvailability = availability != Instances.AVAILABILITY_FREE;
                 if (meetsCalendar && meetsAvailability) {
                     if (DEBUG) Log.d(TAG, "  MEETS CALENDAR & AVAILABILITY");
diff --git a/services/core/java/com/android/server/notification/ZenModeConditions.java b/services/core/java/com/android/server/notification/ZenModeConditions.java
index 0945065..86ca97d 100644
--- a/services/core/java/com/android/server/notification/ZenModeConditions.java
+++ b/services/core/java/com/android/server/notification/ZenModeConditions.java
@@ -99,9 +99,7 @@
     @Override
     public void onServiceAdded(ComponentName component) {
         if (DEBUG) Log.d(TAG, "onServiceAdded " + component);
-        if (isAutomaticActive(component)) {
-            mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
-        }
+        mHelper.setConfigAsync(mHelper.getConfig(), "zmc.onServiceAdded");
     }
 
     @Override
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index eb49e9f..60e00a9 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -643,18 +643,22 @@
                 dispatchOnPolicyChanged();
             }
             mConfig = config;
-            final String val = Integer.toString(config.hashCode());
-            Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
-            if (!evaluateZenMode(reason, setRingerMode)) {
-                applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
-            }
-            mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+            mHandler.postApplyConfig(config, reason, setRingerMode);
             return true;
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
     }
 
+    private void applyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+        final String val = Integer.toString(config.hashCode());
+        Global.putString(mContext.getContentResolver(), Global.ZEN_MODE_CONFIG_ETAG, val);
+        if (!evaluateZenMode(reason, setRingerMode)) {
+            applyRestrictions();  // evaluateZenMode will also apply restrictions if changed
+        }
+        mConditions.evaluateConfig(config, true /*processSubscriptions*/);
+    }
+
     private int getZenModeSetting() {
         return Global.getInt(mContext.getContentResolver(), Global.ZEN_MODE, Global.ZEN_MODE_OFF);
     }
@@ -1071,14 +1075,23 @@
         private static final int MSG_DISPATCH = 1;
         private static final int MSG_METRICS = 2;
         private static final int MSG_SET_CONFIG = 3;
+        private static final int MSG_APPLY_CONFIG = 4;
 
         private final class ConfigMessageData {
             public final ZenModeConfig config;
             public final String reason;
+            public final boolean setRingerMode;
 
             ConfigMessageData(ZenModeConfig config, String reason) {
                 this.config = config;
                 this.reason = reason;
+                this.setRingerMode = false;
+            }
+
+            ConfigMessageData(ZenModeConfig config, String reason, boolean setRingerMode) {
+                this.config = config;
+                this.reason = reason;
+                this.setRingerMode = setRingerMode;
             }
         }
 
@@ -1102,6 +1115,11 @@
             sendMessage(obtainMessage(MSG_SET_CONFIG, new ConfigMessageData(config, reason)));
         }
 
+        private void postApplyConfig(ZenModeConfig config, String reason, boolean setRingerMode) {
+            sendMessage(obtainMessage(MSG_APPLY_CONFIG,
+                    new ConfigMessageData(config, reason, setRingerMode)));
+        }
+
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
@@ -1112,11 +1130,15 @@
                     mMetrics.emit();
                     break;
                 case MSG_SET_CONFIG:
-                    ConfigMessageData configData = (ConfigMessageData)msg.obj;
+                    ConfigMessageData configData = (ConfigMessageData) msg.obj;
                     synchronized (mConfig) {
                         setConfigLocked(configData.config, configData.reason);
                     }
                     break;
+                case MSG_APPLY_CONFIG:
+                    ConfigMessageData applyConfigData = (ConfigMessageData) msg.obj;
+                    applyConfig(applyConfigData.config, applyConfigData.reason,
+                            applyConfigData.setRingerMode);
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0633625..f21966d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -1104,6 +1104,7 @@
     final @NonNull String mRequiredInstallerPackage;
     final @Nullable String mSetupWizardPackage;
     final @NonNull String mServicesSystemSharedLibraryPackageName;
+    final @NonNull String mSharedSystemSharedLibraryPackageName;
 
     private final PackageUsage mPackageUsage = new PackageUsage();
 
@@ -1152,16 +1153,24 @@
                     try {
                         f = file.startWrite();
                         BufferedOutputStream out = new BufferedOutputStream(f);
-                        FileUtils.setPermissions(file.getBaseFile().getPath(), 0640, SYSTEM_UID, PACKAGE_INFO_GID);
+                        FileUtils.setPermissions(file.getBaseFile().getPath(),
+                                0640, SYSTEM_UID, PACKAGE_INFO_GID);
                         StringBuilder sb = new StringBuilder();
+
+                        sb.append(USAGE_FILE_MAGIC_VERSION_1);
+                        sb.append('\n');
+                        out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
+
                         for (PackageParser.Package pkg : mPackages.values()) {
-                            if (pkg.mLastPackageUsageTimeInMills == 0) {
+                            if (pkg.getLatestPackageUseTimeInMills() == 0L) {
                                 continue;
                             }
                             sb.setLength(0);
                             sb.append(pkg.packageName);
-                            sb.append(' ');
-                            sb.append((long)pkg.mLastPackageUsageTimeInMills);
+                            for (long usageTimeInMillis : pkg.mLastPackageUsageTimeInMills) {
+                                sb.append(' ');
+                                sb.append(usageTimeInMillis);
+                            }
                             sb.append('\n');
                             out.write(sb.toString().getBytes(StandardCharsets.US_ASCII));
                         }
@@ -1185,28 +1194,12 @@
                 try {
                     in = new BufferedInputStream(file.openRead());
                     StringBuffer sb = new StringBuffer();
-                    while (true) {
-                        String packageName = readToken(in, sb, ' ');
-                        if (packageName == null) {
-                            break;
-                        }
-                        String timeInMillisString = readToken(in, sb, '\n');
-                        if (timeInMillisString == null) {
-                            throw new IOException("Failed to find last usage time for package "
-                                                  + packageName);
-                        }
-                        PackageParser.Package pkg = mPackages.get(packageName);
-                        if (pkg == null) {
-                            continue;
-                        }
-                        long timeInMillis;
-                        try {
-                            timeInMillis = Long.parseLong(timeInMillisString);
-                        } catch (NumberFormatException e) {
-                            throw new IOException("Failed to parse " + timeInMillisString
-                                                  + " as a long.", e);
-                        }
-                        pkg.mLastPackageUsageTimeInMills = timeInMillis;
+
+                    String firstLine = readLine(in, sb);
+                    if (firstLine.equals(USAGE_FILE_MAGIC_VERSION_1)) {
+                        readVersion1LP(in, sb);
+                    } else {
+                        readVersion0LP(in, sb, firstLine);
                     }
                 } catch (FileNotFoundException expected) {
                     mIsHistoricalPackageUsageAvailable = false;
@@ -1219,6 +1212,76 @@
             mLastWritten.set(SystemClock.elapsedRealtime());
         }
 
+        private void readVersion0LP(InputStream in, StringBuffer sb, String firstLine)
+                throws IOException {
+            // Initial version of the file had no version number and stored one
+            // package-timestamp pair per line.
+            // Note that the first line has already been read from the InputStream.
+            String line = firstLine;
+            while (true) {
+                if (line == null) {
+                    break;
+                }
+
+                String[] tokens = line.split(" ");
+                if (tokens.length != 2) {
+                    throw new IOException("Failed to parse " + line +
+                            " as package-timestamp pair.");
+                }
+
+                String packageName = tokens[0];
+                PackageParser.Package pkg = mPackages.get(packageName);
+                if (pkg == null) {
+                    continue;
+                }
+
+                long timestamp = parseAsLong(tokens[1]);
+                for (int reason = 0;
+                        reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
+                        reason++) {
+                    pkg.mLastPackageUsageTimeInMills[reason] = timestamp;
+                }
+
+                line = readLine(in, sb);
+            }
+        }
+
+        private void readVersion1LP(InputStream in, StringBuffer sb) throws IOException {
+            // Version 1 of the file started with the corresponding version
+            // number and then stored a package name and eight timestamps per line.
+            String line;
+            while ((line = readLine(in, sb)) != null) {
+                String[] tokens = line.split(" ");
+                if (tokens.length != PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT + 1) {
+                    throw new IOException("Failed to parse " + line + " as a timestamp array.");
+                }
+
+                String packageName = tokens[0];
+                PackageParser.Package pkg = mPackages.get(packageName);
+                if (pkg == null) {
+                    continue;
+                }
+
+                for (int reason = 0;
+                        reason < PackageManager.NOTIFY_PACKAGE_USE_REASONS_COUNT;
+                        reason++) {
+                    pkg.mLastPackageUsageTimeInMills[reason] = parseAsLong(tokens[reason + 1]);
+                }
+            }
+        }
+
+        private long parseAsLong(String token) throws IOException {
+            try {
+                return Long.parseLong(token);
+            } catch (NumberFormatException e) {
+                throw new IOException("Failed to parse " + token + " as a long.", e);
+            }
+        }
+
+        private String readLine(InputStream in, StringBuffer sb) throws IOException {
+            return readToken(in, sb, '\n');
+        }
+
         private String readToken(InputStream in, StringBuffer sb, char endOfToken)
                 throws IOException {
             sb.setLength(0);
@@ -1243,6 +1306,9 @@
             File fname = new File(systemDir, "package-usage.list");
             return new AtomicFile(fname);
         }
+
+        private static final String USAGE_FILE_MAGIC = "PACKAGE_USAGE__VERSION_";
+        private static final String USAGE_FILE_MAGIC_VERSION_1 = USAGE_FILE_MAGIC + "1";
     }
 
     class PackageHandler extends Handler {
@@ -2647,7 +2713,7 @@
                         mIntentFilterVerifierComponent);
                 mServicesSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                         PackageManager.SYSTEM_SHARED_LIBRARY_SERVICES);
-                getRequiredSharedLibraryLPr(
+                mSharedSystemSharedLibraryPackageName = getRequiredSharedLibraryLPr(
                         PackageManager.SYSTEM_SHARED_LIBRARY_SHARED);
             } else {
                 mRequiredVerifierPackage = null;
@@ -2655,6 +2721,7 @@
                 mIntentFilterVerifierComponent = null;
                 mIntentFilterVerifier = null;
                 mServicesSystemSharedLibraryPackageName = null;
+                mSharedSystemSharedLibraryPackageName = null;
             }
 
             mInstallerService = new PackageInstallerService(context, this);
@@ -3630,6 +3697,13 @@
     }
 
     @Override
+    public @NonNull String getSharedSystemSharedLibraryPackageName() {
+        synchronized (mPackages) {
+            return mSharedSystemSharedLibraryPackageName;
+        }
+    }
+
+    @Override
     public @NonNull ParceledListSlice<FeatureInfo> getSystemAvailableFeatures() {
         synchronized (mPackages) {
             final ArrayList<FeatureInfo> res = new ArrayList<>(mAvailableFeatures.values());
@@ -7130,13 +7204,13 @@
     }
 
     @Override
-    public void notifyPackageUse(String packageName) {
+    public void notifyPackageUse(String packageName, int reason) {
         synchronized (mPackages) {
             PackageParser.Package p = mPackages.get(packageName);
             if (p == null) {
                 return;
             }
-            p.mLastPackageUsageTimeInMills = System.currentTimeMillis();
+            p.mLastPackageUsageTimeInMills[reason] = System.currentTimeMillis();
         }
     }
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
index f79d6ee..3c065ae 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceUtils.java
@@ -69,7 +69,7 @@
         long now = System.currentTimeMillis();
         for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) {
             PackageParser.Package pkg = i.next();
-            long then = pkg.mLastPackageUsageTimeInMills;
+            long then = pkg.getLatestPackageUseTimeInMills();
             if (then + dexOptLRUThresholdInMills < now) {
                 if (DEBUG_DEXOPT) {
                     Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " +
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 93e4d31..7ea5919 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -632,15 +632,6 @@
         intent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
         intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
         mContext.sendBroadcastAsUser(intent, parentHandle);
-
-        //TODO: remove once Launcher3 is updated.
-        Intent oldIntent = new Intent(Intent.ACTION_MANAGED_PROFILE_AVAILABILITY_CHANGED);
-        oldIntent.putExtra(Intent.EXTRA_QUIET_MODE, inQuietMode);
-        oldIntent.putExtra(Intent.EXTRA_USER, profileHandle);
-        oldIntent.putExtra(Intent.EXTRA_USER_HANDLE, profileHandle.getIdentifier());
-        oldIntent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY);
-        mContext.sendBroadcastAsUser(oldIntent, parentHandle);
-
     }
 
     @Override
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 007190d..9f31f4f 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3301,6 +3301,7 @@
                         shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                         try {
                             startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+                            dismissKeyboardShortcutsMenu();
                         } catch (ActivityNotFoundException ex) {
                             Slog.w(TAG, "Dropping shortcut key combination because "
                                     + "the activity to which it is registered was not found: "
@@ -3327,6 +3328,7 @@
                     shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                     try {
                         startActivityAsUser(shortcutIntent, UserHandle.CURRENT);
+                        dismissKeyboardShortcutsMenu();
                     } catch (ActivityNotFoundException ex) {
                         Slog.w(TAG, "Dropping shortcut key combination because "
                                 + "the activity to which it is registered was not found: "
@@ -3345,6 +3347,7 @@
                 intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                 try {
                     startActivityAsUser(intent, UserHandle.CURRENT);
+                    dismissKeyboardShortcutsMenu();
                 } catch (ActivityNotFoundException ex) {
                     Slog.w(TAG, "Dropping application launch key because "
                             + "the activity to which it is registered was not found: "
@@ -3635,6 +3638,13 @@
         }
     }
 
+    private void dismissKeyboardShortcutsMenu() {
+        StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
+        if (statusbar != null) {
+            statusbar.dismissKeyboardShortcutsMenu();
+        }
+    }
+
     private void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHome) {
         mPreloadedRecentApps = false; // preloading no longer needs to be canceled
         StatusBarManagerInternal statusbar = getStatusBarManagerInternal();
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index 8cd536d..12a2d2e 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -143,7 +143,6 @@
     private static final int WAKE_LOCK_STAY_AWAKE = 1 << 5; // only set if already awake
     private static final int WAKE_LOCK_DOZE = 1 << 6;
     private static final int WAKE_LOCK_DRAW = 1 << 7;
-    private static final int WAKE_LOCK_SUSTAINED_PERFORMANCE = 1 << 8;
 
     // Summarizes the user activity state.
     private static final int USER_ACTIVITY_SCREEN_BRIGHT = 1 << 0;
@@ -162,7 +161,6 @@
 
     // Power hints defined in hardware/libhardware/include/hardware/power.h.
     private static final int POWER_HINT_LOW_POWER = 5;
-    private static final int POWER_HINT_SUSTAINED_PERFORMANCE = 6;
     private static final int POWER_HINT_VR_MODE = 7;
 
     // Power features defined in hardware/libhardware/include/hardware/power.h.
@@ -470,9 +468,6 @@
     // True if we are currently in light device idle mode.
     private boolean mLightDeviceIdleMode;
 
-    // True if we are currently in sustained performance mode.
-    private boolean mSustainedPerformanceMode;
-
     // Set of app ids that we will always respect the wake locks for.
     int[] mDeviceIdleWhitelist = new int[0];
 
@@ -481,8 +476,6 @@
 
     private final SparseIntArray mUidState = new SparseIntArray();
 
-    private final SparseIntArray mSustainedPerformanceUid = new SparseIntArray();
-
     // True if theater mode is enabled
     private boolean mTheaterModeEnabled;
 
@@ -879,12 +872,6 @@
                     throw new IllegalArgumentException("Wake lock is already dead.");
                 }
                 mWakeLocks.add(wakeLock);
-
-                if ((flags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                        == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
-                    int numberWakelock = mSustainedPerformanceUid.get(uid);
-                    mSustainedPerformanceUid.put(uid, numberWakelock + 1);
-                }
                 setWakeLockDisabledStateLocked(wakeLock);
                 notifyAcquire = true;
             }
@@ -953,17 +940,6 @@
                 mRequestWaitForNegativeProximity = true;
             }
 
-
-            if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
-                int numberWakelock = mSustainedPerformanceUid.get(wakeLock.mOwnerUid);
-                if (numberWakelock == 1) {
-                    mSustainedPerformanceUid.delete(wakeLock.mOwnerUid);
-                } else {
-                    mSustainedPerformanceUid.put(wakeLock.mOwnerUid, numberWakelock - 1);
-                }
-            }
-
             wakeLock.mLock.unlinkToDeath(wakeLock, 0);
             removeWakeLockLocked(wakeLock, index);
         }
@@ -1586,10 +1562,6 @@
                         break;
                     case PowerManager.DRAW_WAKE_LOCK:
                         mWakeLockSummary |= WAKE_LOCK_DRAW;
-                    case PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK:
-                        if (!wakeLock.mDisabled) {
-                            mWakeLockSummary |= WAKE_LOCK_SUSTAINED_PERFORMANCE;
-                        }
                         break;
                 }
             }
@@ -2288,14 +2260,6 @@
         if (autoSuspend && mDecoupleHalAutoSuspendModeFromDisplayConfig) {
             setHalAutoSuspendModeLocked(true);
         }
-
-        if (mSustainedPerformanceMode
-                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) == 0) {
-            setSustainedPerformanceModeLocked(false);
-        } else if (!mSustainedPerformanceMode
-                && (mWakeLockSummary & WAKE_LOCK_SUSTAINED_PERFORMANCE) != 0) {
-            setSustainedPerformanceModeLocked(true);
-        }
     }
 
     /**
@@ -2394,12 +2358,6 @@
         }
     }
 
-    private void setSustainedPerformanceModeLocked(boolean mode) {
-            mSustainedPerformanceMode = mode;
-            powerHintInternal(POWER_HINT_SUSTAINED_PERFORMANCE,
-                              mSustainedPerformanceMode ? 1 : 0);
-    }
-
     boolean isDeviceIdleModeInternal() {
         synchronized (mLock) {
             return mDeviceIdleMode;
@@ -2531,7 +2489,7 @@
     void updateUidProcStateInternal(int uid, int procState) {
         synchronized (mLock) {
             mUidState.put(uid, procState);
-            if (mDeviceIdleMode || mSustainedPerformanceUid.get(uid) != 0) {
+            if (mDeviceIdleMode) {
                 updateWakeLockDisabledStatesLocked();
             }
         }
@@ -2552,9 +2510,7 @@
         for (int i = 0; i < numWakeLocks; i++) {
             final WakeLock wakeLock = mWakeLocks.get(i);
             if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.PARTIAL_WAKE_LOCK
-                    || (wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                    == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK) {
+                    == PowerManager.PARTIAL_WAKE_LOCK) {
                 if (setWakeLockDisabledStateLocked(wakeLock)) {
                     changed = true;
                     if (wakeLock.mDisabled) {
@@ -2573,9 +2529,9 @@
     }
 
     private boolean setWakeLockDisabledStateLocked(WakeLock wakeLock) {
-        boolean disabled = false;
         if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
                 == PowerManager.PARTIAL_WAKE_LOCK) {
+            boolean disabled = false;
             if (mDeviceIdleMode) {
                 final int appid = UserHandle.getAppId(wakeLock.mOwnerUid);
                 // If we are in idle mode, we will ignore all partial wake locks that are
@@ -2589,16 +2545,10 @@
                     disabled = true;
                 }
             }
-        } else if ((wakeLock.mFlags & PowerManager.WAKE_LOCK_LEVEL_MASK)
-                == PowerManager.SUSTAINED_PERFORMANCE_WAKE_LOCK
-                && mUidState.get(wakeLock.mOwnerUid,
-                                 ActivityManager.PROCESS_STATE_CACHED_EMPTY)
-                > ActivityManager.PROCESS_STATE_TOP) {
-            disabled = true;
-        }
-        if (wakeLock.mDisabled != disabled) {
-            wakeLock.mDisabled = disabled;
-            return true;
+            if (wakeLock.mDisabled != disabled) {
+                wakeLock.mDisabled = disabled;
+                return true;
+            }
         }
         return false;
     }
@@ -2806,7 +2756,6 @@
             pw.println("  mBatteryLevelLow=" + mBatteryLevelLow);
             pw.println("  mLightDeviceIdleMode=" + mLightDeviceIdleMode);
             pw.println("  mDeviceIdleMode=" + mDeviceIdleMode);
-            pw.println("  mSustainedPerformanceMode=" + mSustainedPerformanceMode);
             pw.println("  mDeviceIdleWhitelist=" + Arrays.toString(mDeviceIdleWhitelist));
             pw.println("  mDeviceIdleTempWhitelist=" + Arrays.toString(mDeviceIdleTempWhitelist));
             pw.println("  mLastWakeTime=" + TimeUtils.formatUptime(mLastWakeTime));
@@ -2921,14 +2870,6 @@
             pw.println();
             pw.println("Display Power: " + mDisplayPowerCallbacks);
 
-            pw.println();
-            pw.println("Sustained Performance UIDs:");
-            for (int i=0; i<mSustainedPerformanceUid.size(); i++) {
-                pw.print("  UID "); UserHandle.formatUid(pw, mSustainedPerformanceUid.keyAt(i));
-                pw.print(": "); pw.println(mSustainedPerformanceUid.valueAt(i));
-            }
-
-
             wcd = mWirelessChargerDetector;
         }
 
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
index 38a3d01..52b2439 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerInternal.java
@@ -37,6 +37,7 @@
 
     void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
 
+    void dismissKeyboardShortcutsMenu();
     void toggleKeyboardShortcutsMenu(int deviceId);
 
     /**
diff --git a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
index 9020677..c630d4a 100644
--- a/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
+++ b/services/core/java/com/android/server/statusbar/StatusBarManagerService.java
@@ -277,6 +277,15 @@
         }
 
         @Override
+        public void dismissKeyboardShortcutsMenu() {
+            if (mBar != null) {
+                try {
+                    mBar.dismissKeyboardShortcutsMenu();
+                } catch (RemoteException ex) {}
+            }
+        }
+
+        @Override
         public void toggleKeyboardShortcutsMenu(int deviceId) {
             if (mBar != null) {
                 try {
diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java
new file mode 100644
index 0000000..557e9c8
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvRemoteProviderProxy.java
@@ -0,0 +1,647 @@
+/*
+ * 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.server.tv;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.ServiceConnection;
+import android.media.tv.ITvRemoteProvider;
+import android.media.tv.ITvRemoteServiceInput;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.io.PrintWriter;
+import java.lang.ref.WeakReference;
+
+/**
+ * Maintains a connection to a tv remote provider service.
+ */
+final class TvRemoteProviderProxy implements ServiceConnection {
+    private static final String TAG = "TvRemoteProvProxy";  // max. 23 chars
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
+    private static final boolean DEBUG_KEY = false;
+
+
+    // This should match TvRemoteProvider.ACTION_TV_REMOTE_PROVIDER
+    protected static final String SERVICE_INTERFACE =
+            "com.android.media.tv.remoteprovider.TvRemoteProvider";
+    private final Context mContext;
+    private final ComponentName mComponentName;
+    private final int mUserId;
+    private final int mUid;
+    private final Handler mHandler;
+
+    /**
+     * State guarded by mLock.
+     *  This is the first lock in sequence for an incoming call.
+     *  The second lock is always {@link TvRemoteService#mLock}
+     *
+     *  There are currently no methods that break this sequence.
+     */
+    private final Object mLock = new Object();
+
+    private ProviderMethods mProviderMethods;
+    // Connection state
+    private boolean mRunning;
+    private boolean mBound;
+    private Connection mActiveConnection;
+    private boolean mConnectionReady;
+
+    public TvRemoteProviderProxy(Context context, ComponentName componentName, int userId,
+                                 int uid) {
+        mContext = context;
+        mComponentName = componentName;
+        mUserId = userId;
+        mUid = uid;
+        mHandler = new Handler();
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        pw.println(prefix + "Proxy");
+        pw.println(prefix + "  mUserId=" + mUserId);
+        pw.println(prefix + "  mRunning=" + mRunning);
+        pw.println(prefix + "  mBound=" + mBound);
+        pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
+        pw.println(prefix + "  mConnectionReady=" + mConnectionReady);
+    }
+
+    public void setProviderSink(ProviderMethods provider) {
+        mProviderMethods = provider;
+    }
+
+    public boolean hasComponentName(String packageName, String className) {
+        return mComponentName.getPackageName().equals(packageName)
+                && mComponentName.getClassName().equals(className);
+    }
+
+    public void start() {
+        if (!mRunning) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Starting");
+            }
+
+            mRunning = true;
+            updateBinding();
+        }
+    }
+
+    public void stop() {
+        if (mRunning) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Stopping");
+            }
+
+            mRunning = false;
+            updateBinding();
+        }
+    }
+
+    public void rebindIfDisconnected() {
+        synchronized (mLock) {
+            if (mActiveConnection == null && shouldBind()) {
+                unbind();
+                bind();
+            }
+        }
+    }
+
+    private void updateBinding() {
+        if (shouldBind()) {
+            bind();
+        } else {
+            unbind();
+        }
+    }
+
+    private boolean shouldBind() {
+        return mRunning;
+    }
+
+    private void bind() {
+        if (!mBound) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Binding");
+            }
+
+            Intent service = new Intent(SERVICE_INTERFACE);
+            service.setComponent(mComponentName);
+            try {
+                mBound = mContext.bindServiceAsUser(service, this,
+                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                        new UserHandle(mUserId));
+                if (!mBound && DEBUG) {
+                    Slog.d(TAG, this + ": Bind failed");
+                }
+            } catch (SecurityException ex) {
+                if (DEBUG) {
+                    Slog.d(TAG, this + ": Bind failed", ex);
+                }
+            }
+        }
+    }
+
+    private void unbind() {
+        if (mBound) {
+            if (DEBUG) {
+                Slog.d(TAG, this + ": Unbinding");
+            }
+
+            mBound = false;
+            disconnect();
+            mContext.unbindService(this);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        if (DEBUG) {
+            Slog.d(TAG, this + ": onServiceConnected()");
+        }
+
+        if (mBound) {
+            disconnect();
+
+            ITvRemoteProvider provider = ITvRemoteProvider.Stub.asInterface(service);
+            if (provider != null) {
+                Connection connection = new Connection(provider);
+                if (connection.register()) {
+                    synchronized (mLock) {
+                        mActiveConnection = connection;
+                    }
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": Connected successfully.");
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": Registration failed");
+                    }
+                }
+            } else {
+                Slog.e(TAG, this + ": Service returned invalid remote-control provider binder");
+            }
+        }
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        if (DEBUG) Slog.d(TAG, this + ": Service disconnected");
+        disconnect();
+    }
+
+
+    private void onConnectionReady(Connection connection) {
+        synchronized (mLock) {
+            if (DEBUG) Slog.d(TAG, "onConnectionReady");
+            if (mActiveConnection == connection) {
+                if (DEBUG) Slog.d(TAG, "mConnectionReady = true");
+                mConnectionReady = true;
+            }
+        }
+    }
+
+    private void onConnectionDied(Connection connection) {
+        if (mActiveConnection == connection) {
+            if (DEBUG) Slog.d(TAG, this + ": Service connection died");
+            disconnect();
+        }
+    }
+
+    private void disconnect() {
+        synchronized (mLock) {
+            if (mActiveConnection != null) {
+                mConnectionReady = false;
+                mActiveConnection.dispose();
+                mActiveConnection = null;
+            }
+        }
+    }
+
+    // Provider helpers
+    public void inputBridgeConnected(IBinder token) {
+        synchronized (mLock) {
+            if (DEBUG) Slog.d(TAG, this + ": inputBridgeConnected token: " + token);
+            if (mConnectionReady) {
+                mActiveConnection.onInputBridgeConnected(token);
+            }
+        }
+    }
+
+    public interface ProviderMethods {
+        // InputBridge
+        void openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
+                             int width, int height, int maxPointers);
+
+        void closeInputBridge(TvRemoteProviderProxy provider, IBinder token);
+
+        void clearInputBridge(TvRemoteProviderProxy provider, IBinder token);
+
+        void sendTimeStamp(TvRemoteProviderProxy provider, IBinder token, long timestamp);
+
+        void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode);
+
+        void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode);
+
+        void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId, int x,
+                             int y);
+
+        void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId);
+
+        void sendPointerSync(TvRemoteProviderProxy provider, IBinder token);
+    }
+
+    private final class Connection implements IBinder.DeathRecipient {
+        private final ITvRemoteProvider mTvRemoteProvider;
+        private final RemoteServiceInputProvider mServiceInputProvider;
+
+        public Connection(ITvRemoteProvider provider) {
+            mTvRemoteProvider = provider;
+            mServiceInputProvider = new RemoteServiceInputProvider(this);
+        }
+
+        public boolean register() {
+            if (DEBUG) Slog.d(TAG, "Connection::register()");
+            try {
+                mTvRemoteProvider.asBinder().linkToDeath(this, 0);
+                mTvRemoteProvider.setRemoteServiceInputSink(mServiceInputProvider);
+                mHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        onConnectionReady(Connection.this);
+                    }
+                });
+                return true;
+            } catch (RemoteException ex) {
+                binderDied();
+            }
+            return false;
+        }
+
+        public void dispose() {
+            if (DEBUG) Slog.d(TAG, "Connection::dispose()");
+            mTvRemoteProvider.asBinder().unlinkToDeath(this, 0);
+            mServiceInputProvider.dispose();
+        }
+
+
+        public void onInputBridgeConnected(IBinder token) {
+            if (DEBUG) Slog.d(TAG, this + ": onInputBridgeConnected");
+            try {
+                mTvRemoteProvider.onInputBridgeConnected(token);
+            } catch (RemoteException ex) {
+                Slog.e(TAG, "Failed to deliver onInputBridgeConnected. ", ex);
+            }
+        }
+
+        @Override
+        public void binderDied() {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    onConnectionDied(Connection.this);
+                }
+            });
+        }
+
+        void openInputBridge(final IBinder token, final String name, final int width,
+                             final int height, final int maxPointers) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": openInputBridge," +
+                                " token=" + token + ", name=" + name);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.openInputBridge(TvRemoteProviderProxy.this, token,
+                                    name, width, height, maxPointers);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "openInputBridge, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void closeInputBridge(final IBinder token) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": closeInputBridge," +
+                                " token=" + token);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.closeInputBridge(TvRemoteProviderProxy.this, token);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "closeInputBridge, Invalid connection or incorrect uid: " +
+                                        Binder.getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void clearInputBridge(final IBinder token) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG) {
+                        Slog.d(TAG, this + ": clearInputBridge," +
+                                " token=" + token);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.clearInputBridge(TvRemoteProviderProxy.this, token);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "clearInputBridge, Invalid connection or incorrect uid: " +
+                                        Binder.getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void sendTimestamp(final IBinder token, final long timestamp) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.sendTimeStamp(TvRemoteProviderProxy.this, token,
+                                    timestamp);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "sendTimeStamp, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void sendKeyDown(final IBinder token, final int keyCode) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG_KEY) {
+                        Slog.d(TAG, this + ": sendKeyDown," +
+                                " token=" + token + ", keyCode=" + keyCode);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.sendKeyDown(TvRemoteProviderProxy.this, token,
+                                    keyCode);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "sendKeyDown, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void sendKeyUp(final IBinder token, final int keyCode) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG_KEY) {
+                        Slog.d(TAG, this + ": sendKeyUp," +
+                                " token=" + token + ", keyCode=" + keyCode);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.sendKeyUp(TvRemoteProviderProxy.this, token, keyCode);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "sendKeyUp, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void sendPointerDown(final IBinder token, final int pointerId, final int x, final int y) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG_KEY) {
+                        Slog.d(TAG, this + ": sendPointerDown," +
+                                " token=" + token + ", pointerId=" + pointerId);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.sendPointerDown(TvRemoteProviderProxy.this, token,
+                                    pointerId, x, y);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "sendPointerDown, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void sendPointerUp(final IBinder token, final int pointerId) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG_KEY) {
+                        Slog.d(TAG, this + ": sendPointerUp," +
+                                " token=" + token + ", pointerId=" + pointerId);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.sendPointerUp(TvRemoteProviderProxy.this, token,
+                                    pointerId);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "sendPointerUp, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+
+        void sendPointerSync(final IBinder token) {
+            synchronized (mLock) {
+                if (mActiveConnection == this && Binder.getCallingUid() == mUid) {
+                    if (DEBUG_KEY) {
+                        Slog.d(TAG, this + ": sendPointerSync," +
+                                " token=" + token);
+                    }
+                    final long idToken = Binder.clearCallingIdentity();
+                    try {
+                        if (mProviderMethods != null) {
+                            mProviderMethods.sendPointerSync(TvRemoteProviderProxy.this, token);
+                        }
+                    } finally {
+                        Binder.restoreCallingIdentity(idToken);
+                    }
+                } else {
+                    if (DEBUG) {
+                        Slog.w(TAG,
+                                "sendPointerSync, Invalid connection or incorrect uid: " + Binder
+                                        .getCallingUid());
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Receives events from the connected provider.
+     * <p>
+     * This inner class is static and only retains a weak reference to the connection
+     * to prevent the client from being leaked in case the service is holding an
+     * active reference to the client's callback.
+     * </p>
+     */
+    private static final class RemoteServiceInputProvider extends ITvRemoteServiceInput.Stub {
+        private final WeakReference<Connection> mConnectionRef;
+
+        public RemoteServiceInputProvider(Connection connection) {
+            mConnectionRef = new WeakReference<Connection>(connection);
+        }
+
+        public void dispose() {
+            // Terminate the connection.
+            mConnectionRef.clear();
+        }
+
+        @Override
+        public void openInputBridge(IBinder token, String name, int width,
+                                    int height, int maxPointers) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.openInputBridge(token, name, width, height, maxPointers);
+            }
+        }
+
+        @Override
+        public void closeInputBridge(IBinder token) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.closeInputBridge(token);
+            }
+        }
+
+        @Override
+        public void clearInputBridge(IBinder token) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.clearInputBridge(token);
+            }
+        }
+
+        @Override
+        public void sendTimestamp(IBinder token, long timestamp) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.sendTimestamp(token, timestamp);
+            }
+        }
+
+        @Override
+        public void sendKeyDown(IBinder token, int keyCode) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.sendKeyDown(token, keyCode);
+            }
+        }
+
+        @Override
+        public void sendKeyUp(IBinder token, int keyCode) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.sendKeyUp(token, keyCode);
+            }
+        }
+
+        @Override
+        public void sendPointerDown(IBinder token, int pointerId, int x, int y)
+                throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.sendPointerDown(token, pointerId, x, y);
+            }
+        }
+
+        @Override
+        public void sendPointerUp(IBinder token, int pointerId) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.sendPointerUp(token, pointerId);
+            }
+        }
+
+        @Override
+        public void sendPointerSync(IBinder token) throws RemoteException {
+            Connection connection = mConnectionRef.get();
+            if (connection != null) {
+                connection.sendPointerSync(token);
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
new file mode 100644
index 0000000..d27970f
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvRemoteProviderWatcher.java
@@ -0,0 +1,221 @@
+/*
+ * 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.server.tv;
+
+import android.Manifest;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.util.Log;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.Collections;
+
+/**
+ * Watches for emote provider services to be installed.
+ * Adds a provider for each registered service.
+ *
+ * @see TvRemoteProviderProxy
+ */
+final class TvRemoteProviderWatcher {
+
+    private static final String TAG = "TvRemoteProvWatcher";  // max. 23 chars
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
+
+    private final Context mContext;
+    private final ProviderMethods mProvider;
+    private final Handler mHandler;
+    private final PackageManager mPackageManager;
+    private final ArrayList<TvRemoteProviderProxy> mProviderProxies = new ArrayList<>();
+    private final int mUserId;
+    private final String mUnbundledServicePackage;
+
+    private boolean mRunning;
+
+    public TvRemoteProviderWatcher(Context context, ProviderMethods provider, Handler handler) {
+        mContext = context;
+        mProvider = provider;
+        mHandler = handler;
+        mUserId = UserHandle.myUserId();
+        mPackageManager = context.getPackageManager();
+        mUnbundledServicePackage = context.getString(
+                com.android.internal.R.string.config_tvRemoteServicePackage);
+    }
+
+    public void start() {
+        if (DEBUG) Slog.d(TAG, "start()");
+        if (!mRunning) {
+            mRunning = true;
+
+            IntentFilter filter = new IntentFilter();
+            filter.addAction(Intent.ACTION_PACKAGE_ADDED);
+            filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
+            filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+            filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
+            filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
+            filter.addDataScheme("package");
+            mContext.registerReceiverAsUser(mScanPackagesReceiver,
+                    new UserHandle(mUserId), filter, null, mHandler);
+
+            // Scan packages.
+            // Also has the side-effect of restarting providers if needed.
+            mHandler.post(mScanPackagesRunnable);
+        }
+    }
+
+    public void stop() {
+        if (mRunning) {
+            mRunning = false;
+
+            mContext.unregisterReceiver(mScanPackagesReceiver);
+            mHandler.removeCallbacks(mScanPackagesRunnable);
+
+            // Stop all providers.
+            for (int i = mProviderProxies.size() - 1; i >= 0; i--) {
+                mProviderProxies.get(i).stop();
+            }
+        }
+    }
+
+    private void scanPackages() {
+        if (!mRunning) {
+            return;
+        }
+
+        if (DEBUG) Log.d(TAG, "scanPackages()");
+        // Add providers for all new services.
+        // Reorder the list so that providers left at the end will be the ones to remove.
+        int targetIndex = 0;
+        Intent intent = new Intent(TvRemoteProviderProxy.SERVICE_INTERFACE);
+        for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
+                intent, 0, mUserId)) {
+            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
+            if (serviceInfo != null && verifyServiceTrusted(serviceInfo)) {
+                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
+                if (sourceIndex < 0) {
+                    TvRemoteProviderProxy providerProxy =
+                            new TvRemoteProviderProxy(mContext,
+                                    new ComponentName(serviceInfo.packageName, serviceInfo.name),
+                                    mUserId, serviceInfo.applicationInfo.uid);
+                    providerProxy.start();
+                    mProviderProxies.add(targetIndex++, providerProxy);
+                    mProvider.addProvider(providerProxy);
+                } else if (sourceIndex >= targetIndex) {
+                    TvRemoteProviderProxy provider = mProviderProxies.get(sourceIndex);
+                    provider.start(); // restart the provider if needed
+                    provider.rebindIfDisconnected();
+                    Collections.swap(mProviderProxies, sourceIndex, targetIndex++);
+                }
+            }
+        }
+        if (DEBUG) Log.d(TAG, "scanPackages() targetIndex " + targetIndex);
+        // Remove providers for missing services.
+        if (targetIndex < mProviderProxies.size()) {
+            for (int i = mProviderProxies.size() - 1; i >= targetIndex; i--) {
+                TvRemoteProviderProxy providerProxy = mProviderProxies.get(i);
+                mProvider.removeProvider(providerProxy);
+                mProviderProxies.remove(providerProxy);
+                providerProxy.stop();
+            }
+        }
+    }
+
+    private boolean verifyServiceTrusted(ServiceInfo serviceInfo) {
+        if (serviceInfo.permission == null || !serviceInfo.permission.equals(
+                Manifest.permission.BIND_TV_REMOTE_SERVICE)) {
+            // If the service does not require this permission then any app could
+            // potentially bind to it and cause the atv remote provider service to
+            // misbehave.  So we only want to trust providers that require the
+            // correct permissions.
+            Slog.w(TAG, "Ignoring atv remote provider service because it did not "
+                    + "require the BIND_TV_REMOTE_SERVICE permission in its manifest: "
+                    + serviceInfo.packageName + "/" + serviceInfo.name);
+            return false;
+        }
+
+        // Check if package name is white-listed here.
+        if (!serviceInfo.packageName.equals(mUnbundledServicePackage)) {
+            Slog.w(TAG, "Ignoring atv remote provider service because the package has not "
+                    + "been set and/or whitelisted: "
+                    + serviceInfo.packageName + "/" + serviceInfo.name);
+            return false;
+        }
+
+        if (!hasNecessaryPermissions(serviceInfo.packageName)) {
+            // If the service does not have permission to be
+            // a virtual tv remote controller, do not trust it.
+            Slog.w(TAG, "Ignoring atv remote provider service because its package does not "
+                    + "have TV_VIRTUAL_REMOTE_CONTROLLER permission: " + serviceInfo.packageName);
+            return false;
+        }
+
+        // Looks good.
+        return true;
+    }
+
+    // Returns true only if these permissions are present in calling package.
+    // Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER : virtual remote controller on TV
+    private boolean hasNecessaryPermissions(String packageName) {
+        if ((mPackageManager.checkPermission(Manifest.permission.TV_VIRTUAL_REMOTE_CONTROLLER,
+                        packageName) == PackageManager.PERMISSION_GRANTED)) {
+            return true;
+        }
+        return false;
+    }
+
+    private int findProvider(String packageName, String className) {
+        int count = mProviderProxies.size();
+        for (int i = 0; i < count; i++) {
+            TvRemoteProviderProxy provider = mProviderProxies.get(i);
+            if (provider.hasComponentName(packageName, className)) {
+                return i;
+            }
+        }
+        return -1;
+    }
+
+    private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) {
+                Slog.d(TAG, "Received package manager broadcast: " + intent);
+            }
+            mHandler.post(mScanPackagesRunnable);
+        }
+    };
+
+    private final Runnable mScanPackagesRunnable = new Runnable() {
+        @Override
+        public void run() {
+            scanPackages();
+        }
+    };
+
+    public interface ProviderMethods {
+        void addProvider(TvRemoteProviderProxy providerProxy);
+
+        void removeProvider(TvRemoteProviderProxy providerProxy);
+    }
+}
diff --git a/services/core/java/com/android/server/tv/TvRemoteService.java b/services/core/java/com/android/server/tv/TvRemoteService.java
new file mode 100644
index 0000000..961c992
--- /dev/null
+++ b/services/core/java/com/android/server/tv/TvRemoteService.java
@@ -0,0 +1,388 @@
+/*
+ * 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.server.tv;
+
+import android.content.Context;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.Looper;
+import android.os.Message;
+import android.util.ArrayMap;
+import android.util.Slog;
+
+import com.android.server.SystemService;
+import com.android.server.Watchdog;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Map;
+
+/**
+ * TvRemoteService represents a system service that allows a connected
+ * remote control (emote) service to inject white-listed input events
+ * and call other specified methods for functioning as an emote service.
+ * <p/>
+ * This service is intended for use only by white-listed packages.
+ */
+public class TvRemoteService extends SystemService implements Watchdog.Monitor {
+    private static final String TAG = "TvRemoteService";
+    private static final boolean DEBUG = false;
+    private static final boolean DEBUG_KEYS = false;
+
+    private Map<IBinder, UinputBridge> mBridgeMap = new ArrayMap();
+    private Map<IBinder, TvRemoteProviderProxy> mProviderMap = new ArrayMap();
+    private ArrayList<TvRemoteProviderProxy> mProviderList = new ArrayList<>();
+
+    /**
+     * State guarded by mLock.
+     *  This is the second lock in sequence for an incoming call.
+     *  The first lock is always {@link TvRemoteProviderProxy#mLock}
+     *
+     *  There are currently no methods that break this sequence.
+     *  Special note:
+     *  Outgoing call informInputBridgeConnected(), which is called from
+     *  openInputBridgeInternalLocked() uses a handler thereby relinquishing held locks.
+     */
+    private final Object mLock = new Object();
+
+    public final UserHandler mHandler;
+
+    public TvRemoteService(Context context) {
+        super(context);
+        mHandler = new UserHandler(new UserProvider(TvRemoteService.this), context);
+        Watchdog.getInstance().addMonitor(this);
+    }
+
+    @Override
+    public void onStart() {
+        if (DEBUG) Slog.d(TAG, "onStart()");
+    }
+
+    @Override
+    public void monitor() {
+        synchronized (mLock) { /* check for deadlock */ }
+    }
+
+    @Override
+    public void onBootPhase(int phase) {
+        if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+            if (DEBUG) Slog.d(TAG, "PHASE_THIRD_PARTY_APPS_CAN_START");
+            mHandler.sendEmptyMessage(UserHandler.MSG_START);
+        }
+    }
+
+    //Outgoing calls.
+    private void informInputBridgeConnected(IBinder token) {
+        mHandler.obtainMessage(UserHandler.MSG_INPUT_BRIDGE_CONNECTED, 0, 0, token).sendToTarget();
+    }
+
+    // Incoming calls.
+    private void openInputBridgeInternalLocked(TvRemoteProviderProxy provider, IBinder token,
+                                               String name, int width, int height,
+                                               int maxPointers) {
+        if (DEBUG) {
+            Slog.d(TAG, "openInputBridgeInternalLocked(), token: " + token + ", name: " + name +
+                    ", width: " + width + ", height: " + height + ", maxPointers: " + maxPointers);
+        }
+
+        try {
+            //Create a new bridge, if one does not exist already
+            if (mBridgeMap.containsKey(token)) {
+                if (DEBUG) Slog.d(TAG, "RemoteBridge already exists");
+                // Respond back with success.
+                informInputBridgeConnected(token);
+                return;
+            }
+
+            UinputBridge inputBridge = new UinputBridge(token, name, width, height, maxPointers);
+
+            mBridgeMap.put(token, inputBridge);
+            mProviderMap.put(token, provider);
+
+            // Respond back with success.
+            informInputBridgeConnected(token);
+
+        } catch (IOException ioe) {
+            Slog.e(TAG, "Cannot create device for " + name);
+        }
+    }
+
+    private void closeInputBridgeInternalLocked(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "closeInputBridgeInternalLocked(), token: " + token);
+        }
+
+        // Close an existing RemoteBridge
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.close(token);
+        }
+
+        mBridgeMap.remove(token);
+    }
+
+
+    private void clearInputBridgeInternalLocked(IBinder token) {
+        if (DEBUG) {
+            Slog.d(TAG, "clearInputBridgeInternalLocked(), token: " + token);
+        }
+
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.clear(token);
+        }
+    }
+
+    private void sendTimeStampInternalLocked(IBinder token, long timestamp) {
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.sendTimestamp(token, timestamp);
+        }
+    }
+
+    private void sendKeyDownInternalLocked(IBinder token, int keyCode) {
+        if (DEBUG_KEYS) {
+            Slog.d(TAG, "sendKeyDownInternalLocked(), token: " + token + ", keyCode: " + keyCode);
+        }
+
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.sendKeyDown(token, keyCode);
+        }
+    }
+
+    private void sendKeyUpInternalLocked(IBinder token, int keyCode) {
+        if (DEBUG_KEYS) {
+            Slog.d(TAG, "sendKeyUpInternalLocked(), token: " + token + ", keyCode: " + keyCode);
+        }
+
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.sendKeyUp(token, keyCode);
+        }
+    }
+
+    private void sendPointerDownInternalLocked(IBinder token, int pointerId, int x, int y) {
+        if (DEBUG_KEYS) {
+            Slog.d(TAG, "sendPointerDownInternalLocked(), token: " + token + ", pointerId: " +
+                    pointerId + ", x: " + x + ", y: " + y);
+        }
+
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.sendPointerDown(token, pointerId, x, y);
+        }
+    }
+
+    private void sendPointerUpInternalLocked(IBinder token, int pointerId) {
+        if (DEBUG_KEYS) {
+            Slog.d(TAG, "sendPointerUpInternalLocked(), token: " + token + ", pointerId: " +
+                    pointerId);
+        }
+
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.sendPointerUp(token, pointerId);
+        }
+    }
+
+    private void sendPointerSyncInternalLocked(IBinder token) {
+        if (DEBUG_KEYS) {
+            Slog.d(TAG, "sendPointerSyncInternalLocked(), token: " + token);
+        }
+
+        UinputBridge inputBridge = mBridgeMap.get(token);
+        if (inputBridge != null) {
+            inputBridge.sendPointerSync(token);
+        }
+    }
+
+    private final class UserHandler extends Handler {
+
+        public static final int MSG_START = 1;
+        public static final int MSG_INPUT_BRIDGE_CONNECTED = 2;
+
+        private final TvRemoteProviderWatcher mWatcher;
+        private boolean mRunning;
+
+        public UserHandler(UserProvider provider, Context context) {
+            super(Looper.getMainLooper(), null, true);
+            mWatcher = new TvRemoteProviderWatcher(context, provider, this);
+        }
+
+        @Override
+        public void handleMessage(Message msg) {
+            switch (msg.what) {
+                case MSG_START: {
+                    start();
+                    break;
+                }
+                case MSG_INPUT_BRIDGE_CONNECTED: {
+                    IBinder token = (IBinder) msg.obj;
+                    TvRemoteProviderProxy provider = mProviderMap.get(token);
+                    if (provider != null) {
+                        provider.inputBridgeConnected(token);
+                    }
+                    break;
+                }
+            }
+        }
+
+        private void start() {
+            if (!mRunning) {
+                mRunning = true;
+                mWatcher.start(); // also starts all providers
+            }
+        }
+    }
+
+    private final class UserProvider implements TvRemoteProviderWatcher.ProviderMethods,
+            TvRemoteProviderProxy.ProviderMethods {
+
+        private final TvRemoteService mService;
+
+        public UserProvider(TvRemoteService service) {
+            mService = service;
+        }
+
+        @Override
+        public void openInputBridge(TvRemoteProviderProxy provider, IBinder token, String name,
+                                    int width, int height, int maxPointers) {
+            if (DEBUG) {
+                Slog.d(TAG, "openInputBridge(), token: " + token +
+                        ", name: " + name + ", width: " + width +
+                        ", height: " + height + ", maxPointers: " + maxPointers);
+            }
+
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.openInputBridgeInternalLocked(provider, token, name, width, height,
+                            maxPointers);
+                }
+            }
+        }
+
+        @Override
+        public void closeInputBridge(TvRemoteProviderProxy provider, IBinder token) {
+            if (DEBUG) Slog.d(TAG, "closeInputBridge(), token: " + token);
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.closeInputBridgeInternalLocked(token);
+                    mProviderMap.remove(token);
+                }
+            }
+        }
+
+        @Override
+        public void clearInputBridge(TvRemoteProviderProxy provider, IBinder token) {
+            if (DEBUG) Slog.d(TAG, "clearInputBridge(), token: " + token);
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.clearInputBridgeInternalLocked(token);
+                }
+            }
+        }
+
+        @Override
+        public void sendTimeStamp(TvRemoteProviderProxy provider, IBinder token, long timestamp) {
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.sendTimeStampInternalLocked(token, timestamp);
+                }
+            }
+        }
+
+        @Override
+        public void sendKeyDown(TvRemoteProviderProxy provider, IBinder token, int keyCode) {
+            if (DEBUG_KEYS) {
+                Slog.d(TAG, "sendKeyDown(), token: " + token + ", keyCode: " + keyCode);
+            }
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.sendKeyDownInternalLocked(token, keyCode);
+                }
+            }
+        }
+
+        @Override
+        public void sendKeyUp(TvRemoteProviderProxy provider, IBinder token, int keyCode) {
+            if (DEBUG_KEYS) {
+                Slog.d(TAG, "sendKeyUp(), token: " + token + ", keyCode: " + keyCode);
+            }
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.sendKeyUpInternalLocked(token, keyCode);
+                }
+            }
+        }
+
+        @Override
+        public void sendPointerDown(TvRemoteProviderProxy provider, IBinder token, int pointerId,
+                                    int x, int y) {
+            if (DEBUG_KEYS) {
+                Slog.d(TAG, "sendPointerDown(), token: " + token + ", pointerId: " + pointerId);
+            }
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.sendPointerDownInternalLocked(token, pointerId, x, y);
+                }
+            }
+        }
+
+        @Override
+        public void sendPointerUp(TvRemoteProviderProxy provider, IBinder token, int pointerId) {
+            if (DEBUG_KEYS) {
+                Slog.d(TAG, "sendPointerUp(), token: " + token + ", pointerId: " + pointerId);
+            }
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.sendPointerUpInternalLocked(token, pointerId);
+                }
+            }
+        }
+
+        @Override
+        public void sendPointerSync(TvRemoteProviderProxy provider, IBinder token) {
+            if (DEBUG_KEYS) Slog.d(TAG, "sendPointerSync(), token: " + token);
+            synchronized (mLock) {
+                if (mProviderList.contains(provider)) {
+                    mService.sendPointerSyncInternalLocked(token);
+                }
+            }
+        }
+
+        @Override
+        public void addProvider(TvRemoteProviderProxy provider) {
+            if (DEBUG) Slog.d(TAG, "addProvider " + provider);
+            synchronized (mLock) {
+                provider.setProviderSink(this);
+                mProviderList.add(provider);
+                Slog.d(TAG, "provider: " + provider.toString());
+            }
+        }
+
+        @Override
+        public void removeProvider(TvRemoteProviderProxy provider) {
+            if (DEBUG) Slog.d(TAG, "removeProvider " + provider);
+            synchronized (mLock) {
+                if (mProviderList.remove(provider) == false) {
+                    Slog.e(TAG, "Unknown provider " + provider);
+                }
+            }
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/tv/UinputBridge.java b/services/core/java/com/android/server/tv/UinputBridge.java
new file mode 100644
index 0000000..f910332
--- /dev/null
+++ b/services/core/java/com/android/server/tv/UinputBridge.java
@@ -0,0 +1,139 @@
+/*
+ * 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.server.tv;
+
+import android.os.Binder;
+import android.os.IBinder;
+
+import java.io.IOException;
+
+import dalvik.system.CloseGuard;
+
+/**
+ * Sends the input event to the linux driver.
+ */
+public final class UinputBridge {
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+    private long mPtr;
+    private IBinder mToken = null;
+
+    private static native long nativeOpen(String name, String uniqueId, int width, int height,
+                                          int maxPointers);
+    private static native void nativeClose(long ptr);
+    private static native void nativeClear(long ptr);
+    private static native void nativeSendTimestamp(long ptr, long timestamp);
+    private static native void nativeSendKey(long ptr, int keyCode, boolean down);
+    private static native void nativeSendPointerDown(long ptr, int pointerId, int x, int y);
+    private static native void nativeSendPointerUp(long ptr, int pointerId);
+    private static native void nativeSendPointerSync(long ptr);
+
+    public UinputBridge(IBinder token, String name, int width, int height, int maxPointers)
+                        throws IOException {
+        if (width < 1 || height < 1) {
+            throw new IllegalArgumentException("Touchpad must be at least 1x1.");
+        }
+        if (maxPointers < 1 || maxPointers > 32) {
+            throw new IllegalArgumentException("Touchpad must support between 1 and 32 pointers.");
+        }
+        if (token == null) {
+            throw new IllegalArgumentException("Token cannot be null");
+        }
+        mPtr = nativeOpen(name, token.toString(), width, height, maxPointers);
+        if (mPtr == 0) {
+            throw new IOException("Could not open uinput device " + name);
+        }
+        mToken = token;
+        mCloseGuard.open("close");
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            if (mPtr != 0) {
+                mCloseGuard.warnIfOpen();
+            }
+            close(mToken);
+        } finally {
+            mToken = null;
+            super.finalize();
+        }
+    }
+
+    public void close(IBinder token) {
+        if (isTokenValid(token)) {
+            if (mPtr != 0) {
+                clear(token);
+                nativeClose(mPtr);
+
+                mPtr = 0;
+                mCloseGuard.close();
+            }
+        }
+    }
+
+    public IBinder getToken() {
+        return mToken;
+    }
+
+    protected boolean isTokenValid(IBinder token) {
+        return mToken.equals(token);
+    }
+
+    public void sendTimestamp(IBinder token, long timestamp) {
+        if (isTokenValid(token)) {
+            nativeSendTimestamp(mPtr, timestamp);
+        }
+    }
+
+    public void sendKeyDown(IBinder token, int keyCode) {
+        if (isTokenValid(token)) {
+            nativeSendKey(mPtr, keyCode, true /*down*/);
+        }
+    }
+
+    public void sendKeyUp(IBinder token, int keyCode) {
+        if (isTokenValid(token)) {
+            nativeSendKey(mPtr, keyCode, false /*down*/);
+        }
+    }
+
+    public void sendPointerDown(IBinder token, int pointerId, int x, int y) {
+        if (isTokenValid(token)) {
+            nativeSendPointerDown(mPtr, pointerId, x, y);
+        }
+    }
+
+    public void sendPointerUp(IBinder token, int pointerId) {
+        if (isTokenValid(token)) {
+            nativeSendPointerUp(mPtr, pointerId);
+        }
+    }
+
+    public void sendPointerSync(IBinder token) {
+        if (isTokenValid(token)) {
+            nativeSendPointerSync(mPtr);
+        }
+
+    }
+
+    public void clear(IBinder token) {
+        if (isTokenValid(token)) {
+            nativeClear(mPtr);
+        }
+    }
+
+}
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 91b6914..d6ace91 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -34,7 +34,6 @@
 import android.app.WallpaperInfo;
 import android.app.WallpaperManager;
 import android.app.admin.DevicePolicyManager;
-import android.app.backup.BackupManager;
 import android.app.backup.WallpaperBackupHelper;
 import android.content.BroadcastReceiver;
 import android.content.ComponentName;
@@ -61,6 +60,7 @@
 import android.os.FileUtils;
 import android.os.IBinder;
 import android.os.IRemoteCallback;
+import android.os.Process;
 import android.os.ParcelFileDescriptor;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -205,7 +205,8 @@
             if (path == null) {
                 return;
             }
-            final boolean written = (event == CLOSE_WRITE || event == MOVED_TO);
+            final boolean moved = (event == MOVED_TO);
+            final boolean written = (event == CLOSE_WRITE || moved);
             final File changedFile = new File(mWallpaperDir, path);
 
             // System and system+lock changes happen on the system wallpaper input file;
@@ -224,13 +225,6 @@
                         + " written=" + written);
             }
             synchronized (mLock) {
-                if (sysWallpaperChanged || mWallpaperInfoFile.equals(changedFile)) {
-                    // changing the wallpaper means we'll need to back up the new one
-                    long origId = Binder.clearCallingIdentity();
-                    BackupManager bm = new BackupManager(mContext);
-                    bm.dataChanged();
-                    Binder.restoreCallingIdentity(origId);
-                }
                 if (sysWallpaperChanged || lockWallpaperChanged) {
                     notifyCallbacksLocked(wallpaper);
                     if (wallpaper.wallpaperComponent == null
@@ -244,6 +238,14 @@
                             if (DEBUG) {
                                 Slog.v(TAG, "Wallpaper written; generating crop");
                             }
+                            if (moved) {
+                                // This is a restore, so generate the crop using any just-restored new
+                                // crop guidelines, making sure to preserve our local dimension hints.
+                                if (DEBUG) {
+                                    Slog.v(TAG, "moved-to, therefore restore; reloading metadata");
+                                }
+                                loadSettingsLocked(wallpaper.userId, true);
+                            }
                             generateCrop(wallpaper);
                             if (DEBUG) {
                                 Slog.v(TAG, "Crop done; invoking completion callback");
@@ -491,6 +493,11 @@
         IWallpaperManagerCallback setComplete;
 
         /**
+         * Is the OS allowed to back up this wallpaper imagery?
+         */
+        boolean allowBackup;
+
+        /**
          * Resource name if using a picture from the wallpaper gallery
          */
         String name = "";
@@ -811,7 +818,7 @@
         mMonitor = new MyPackageMonitor();
         mMonitor.register(context, null, UserHandle.ALL, true);
         getWallpaperDir(UserHandle.USER_SYSTEM).mkdirs();
-        loadSettingsLocked(UserHandle.USER_SYSTEM);
+        loadSettingsLocked(UserHandle.USER_SYSTEM, false);
     }
 
     private static File getWallpaperDir(int userId) {
@@ -1024,7 +1031,7 @@
             wallpaper = mWallpaperMap.get(userId);
             if (wallpaper == null) {
                 // Might need to bring it in the first time to establish our rewrite
-                loadSettingsLocked(userId);
+                loadSettingsLocked(userId, false);
                 wallpaper = mWallpaperMap.get(userId);
             }
         }
@@ -1102,7 +1109,7 @@
                 WallpaperData wd = mWallpaperMap.get(user.id);
                 if (wd == null) {
                     // User hasn't started yet, so load her settings to peek at the wallpaper
-                    loadSettingsLocked(user.id);
+                    loadSettingsLocked(user.id, false);
                     wd = mWallpaperMap.get(user.id);
                 }
                 if (wd != null && name.equals(wd.name)) {
@@ -1235,7 +1242,7 @@
             if (wallpaper == null) {
                 // common case, this is the first lookup post-boot of the system or
                 // unified lock, so we bring up the saved state lazily now and recheck.
-                loadSettingsLocked(wallpaperUserId);
+                loadSettingsLocked(wallpaperUserId, false);
                 wallpaper = whichSet.get(wallpaperUserId);
                 if (wallpaper == null) {
                     return null;
@@ -1304,7 +1311,8 @@
 
     @Override
     public ParcelFileDescriptor setWallpaper(String name, String callingPackage,
-            Rect cropHint, Bundle extras, int which, IWallpaperManagerCallback completion) {
+            Rect cropHint, boolean allowBackup, Bundle extras, int which,
+            IWallpaperManagerCallback completion) {
         checkPermission(android.Manifest.permission.SET_WALLPAPER);
 
         if ((which & (FLAG_LOCK|FLAG_SYSTEM)) == 0) {
@@ -1342,6 +1350,9 @@
                     wallpaper.whichPending = which;
                     wallpaper.setComplete = completion;
                     wallpaper.cropHint.set(cropHint);
+                    if ((which & FLAG_SYSTEM) != 0) {
+                        wallpaper.allowBackup = allowBackup;
+                    }
                 }
                 return pfd;
             } finally {
@@ -1651,6 +1662,16 @@
         return !um.hasUserRestriction(UserManager.DISALLOW_SET_WALLPAPER);
     }
 
+    @Override
+    public boolean isWallpaperBackupEligible(int userId) {
+        if (Binder.getCallingUid() != Process.SYSTEM_UID) {
+            throw new SecurityException("Only the system may call isWallpaperBackupEligible");
+        }
+
+        WallpaperData wallpaper = getWallpaperSafeLocked(userId, FLAG_SYSTEM);
+        return (wallpaper != null) ? wallpaper.allowBackup : false;
+    }
+
     private static JournaledFile makeJournaledFile(int userId) {
         final String base = new File(getWallpaperDir(userId), WALLPAPER_INFO).getAbsolutePath();
         return new JournaledFile(new File(base), new File(base + ".tmp"));
@@ -1721,6 +1742,11 @@
             out.attribute(null, "component",
                     wallpaper.wallpaperComponent.flattenToShortString());
         }
+
+        if (wallpaper.allowBackup) {
+            out.attribute(null, "backup", "true");
+        }
+
         out.endTag(null, tag);
     }
 
@@ -1764,7 +1790,7 @@
         if (wallpaper == null) {
             // common case, this is the first lookup post-boot of the system or
             // unified lock, so we bring up the saved state lazily now and recheck.
-            loadSettingsLocked(userId);
+            loadSettingsLocked(userId, false);
             wallpaper = whichSet.get(userId);
             // if it's still null here, this is a lock-only operation and there is not
             // yet a lock-only wallpaper set for this user, so we need to establish
@@ -1788,7 +1814,7 @@
         return wallpaper;
     }
 
-    private void loadSettingsLocked(int userId) {
+    private void loadSettingsLocked(int userId, boolean keepDimensionHints) {
         if (DEBUG) Slog.v(TAG, "loadSettingsLocked");
 
         JournaledFile journal = makeJournaledFile(userId);
@@ -1801,6 +1827,7 @@
         WallpaperData wallpaper = mWallpaperMap.get(userId);
         if (wallpaper == null) {
             wallpaper = new WallpaperData(userId, WALLPAPER, WALLPAPER_CROP);
+            wallpaper.allowBackup = true;
             mWallpaperMap.put(userId, wallpaper);
             if (!wallpaper.cropExists()) {
                 generateCrop(wallpaper);
@@ -1819,7 +1846,7 @@
                     String tag = parser.getName();
                     if ("wp".equals(tag)) {
                         // Common to system + lock wallpapers
-                        parseWallpaperAttributes(parser, wallpaper);
+                        parseWallpaperAttributes(parser, wallpaper, keepDimensionHints);
 
                         // A system wallpaper might also be a live wallpaper
                         String comp = parser.getAttributeValue(null, "component");
@@ -1848,7 +1875,7 @@
                                     WALLPAPER_LOCK_ORIG, WALLPAPER_LOCK_CROP);
                             mLockWallpaperMap.put(userId, lockWallpaper);
                         }
-                        parseWallpaperAttributes(parser, lockWallpaper);
+                        parseWallpaperAttributes(parser, lockWallpaper, false);
                     }
                 }
             } while (type != XmlPullParser.END_DOCUMENT);
@@ -1909,7 +1936,8 @@
         }
     }
 
-    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper) {
+    private void parseWallpaperAttributes(XmlPullParser parser, WallpaperData wallpaper,
+            boolean keepDimensionHints) {
         final String idString = parser.getAttributeValue(null, "id");
         if (idString != null) {
             final int id = wallpaper.wallpaperId = Integer.parseInt(idString);
@@ -1920,9 +1948,11 @@
             wallpaper.wallpaperId = makeWallpaperIdLocked();
         }
 
-        wallpaper.width = Integer.parseInt(parser.getAttributeValue(null, "width"));
-        wallpaper.height = Integer.parseInt(parser
-                .getAttributeValue(null, "height"));
+        if (!keepDimensionHints) {
+            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);
@@ -1932,6 +1962,7 @@
         wallpaper.padding.right = getAttributeInt(parser, "paddingRight", 0);
         wallpaper.padding.bottom = getAttributeInt(parser, "paddingBottom", 0);
         wallpaper.name = parser.getAttributeValue(null, "name");
+        wallpaper.allowBackup = "true".equals(parser.getAttributeValue(null, "backup"));
     }
 
     private int getMaximumSizeDimension() {
@@ -1952,9 +1983,10 @@
         WallpaperData wallpaper = null;
         boolean success = false;
         synchronized (mLock) {
-            loadSettingsLocked(UserHandle.USER_SYSTEM);
+            loadSettingsLocked(UserHandle.USER_SYSTEM, false);
             wallpaper = mWallpaperMap.get(UserHandle.USER_SYSTEM);
             wallpaper.wallpaperId = makeWallpaperIdLocked();    // always bump id at restore
+            wallpaper.allowBackup = true;   // by definition if it was restored
             if (wallpaper.nextWallpaperComponent != null
                     && !wallpaper.nextWallpaperComponent.equals(mImageWallpaper)) {
                 if (!bindWallpaperComponentLocked(wallpaper.nextWallpaperComponent, false, false,
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 11b01cc..9199d10 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -1914,6 +1914,14 @@
                 setAppTransition(transit);
             }
         }
+        if (transit != TRANSIT_DOCK_TASK_FROM_RECENTS
+                && mNextAppTransition == TRANSIT_DOCK_TASK_FROM_RECENTS) {
+
+            // Somebody is trying to start another transition while we are waiting for the docking
+            // window to be drawn. Because TRANSIT_DOCK_TASK_FROM_RECENTS starts prolonged
+            // animations, we need to override it or our prolonged animations will never be ended.
+            setAppTransition(transit);
+        }
         boolean prepared = prepare();
         if (isTransitionSet()) {
             mService.mH.removeMessages(H.APP_TRANSITION_TIMEOUT);
diff --git a/services/core/java/com/android/server/wm/AppWindowAnimator.java b/services/core/java/com/android/server/wm/AppWindowAnimator.java
index aae52e8..abb1bb1 100644
--- a/services/core/java/com/android/server/wm/AppWindowAnimator.java
+++ b/services/core/java/com/android/server/wm/AppWindowAnimator.java
@@ -433,7 +433,7 @@
             WindowStateAnimator winAnimator = mAllAppWinAnimators.get(i);
             if (DEBUG_VISIBILITY) Slog.v(TAG, "performing show on: " + winAnimator);
             winAnimator.performShowLocked();
-            isAnimating |= winAnimator.isAnimating();
+            isAnimating |= winAnimator.isAnimationSet();
         }
         return isAnimating;
     }
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index 545b9db..9f54b53 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -204,7 +204,7 @@
             if (DEBUG_VISIBILITY) {
                 Slog.v(TAG, "Win " + win + ": isDrawn="
                         + win.isDrawnLw()
-                        + ", isAnimating=" + win.mWinAnimator.isAnimating());
+                        + ", isAnimationSet=" + win.mWinAnimator.isAnimationSet());
                 if (!win.isDrawnLw()) {
                     Slog.v(TAG, "Not displayed: s=" +
                             win.mWinAnimator.mSurfaceController
@@ -220,11 +220,11 @@
             numInteresting++;
             if (win.isDrawnLw()) {
                 numDrawn++;
-                if (!win.mWinAnimator.isAnimating()) {
+                if (!win.mWinAnimator.isAnimationSet()) {
                     numVisible++;
                 }
                 nowGone = false;
-            } else if (win.mWinAnimator.isAnimating()) {
+            } else if (win.mWinAnimator.isAnimationSet()) {
                 nowGone = false;
             }
         }
@@ -297,7 +297,7 @@
             // Return true so that the alpha doesn't get cleared.
             if (!win.mAppFreezing
                     && (win.mViewVisibility == View.VISIBLE || mAnimatingWithSavedSurface
-                            || (win.mWinAnimator.isAnimating()
+                            || (win.mWinAnimator.isAnimationSet()
                                     && !service.mAppTransition.isTransitionSet()))
                     && !win.mDestroying
                     && win.isDrawnLw()) {
diff --git a/services/core/java/com/android/server/wm/BoundsAnimationController.java b/services/core/java/com/android/server/wm/BoundsAnimationController.java
index eacdd81..1f44b29 100644
--- a/services/core/java/com/android/server/wm/BoundsAnimationController.java
+++ b/services/core/java/com/android/server/wm/BoundsAnimationController.java
@@ -129,15 +129,19 @@
         public void onAnimationStart(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationStart: mTarget=" + mTarget
                     + " mReplacement=" + mReplacement);
+            // Ensure that we have prepared the target for animation before
+            // we trigger any size changes, so it can swap surfaces
+            // in to appropriate modes, or do as it wishes otherwise.
             if (!mReplacement) {
                 mTarget.onAnimationStart();
             }
 
-            // Ensure that we have prepared the target for animation before
-            // we trigger any size changes, so it can swap surfaces
-            // in to appropriate modes, or do as it wishes otherwise.
+            // Immediately update the task bounds if they have to become larger, but preserve
+            // the starting position so we don't jump at the beginning of the animation.
             if (animatingToLargerSize()) {
-                mTarget.setPinnedStackSize(mFrom, mTo);
+                mTmpRect.set(mFrom.left, mFrom.top,
+                        mFrom.left + mFrozenTaskWidth, mFrom.top + mFrozenTaskHeight);
+                mTarget.setPinnedStackSize(mFrom, mTmpRect);
             }
         }
 
@@ -145,11 +149,15 @@
         public void onAnimationEnd(Animator animation) {
             if (DEBUG) Slog.d(TAG, "onAnimationEnd: mTarget=" + mTarget
                     + " mMoveToFullScreen=" + mMoveToFullScreen + " mWillReplace=" + mWillReplace);
-
-            finishAnimation();
             if (mMoveToFullScreen && !mWillReplace) {
                 mTarget.moveToFullscreen();
             }
+
+            // If we finish the animation before we move the target to fullscreen,
+            // recents may close itself and we may try and resume the previous
+            // fullscreen app leading to churn and flicker after we then move
+            // our target to fullscreen.
+            finishAnimation();
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index b90d0d1..8174c13 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -116,6 +116,11 @@
     private boolean mAnimatingForIme;
     private boolean mAdjustedForIme;
     private WindowState mDelayedImeWin;
+    private boolean mAdjustedForDivider;
+    private float mDividerAnimationStart;
+    private float mDividerAnimationTarget;
+    private float mLastAnimationProgress;
+    private float mLastDividerProgress;
 
     DockedStackDividerController(WindowManagerService service, DisplayContent displayContent) {
         mService = service;
@@ -208,16 +213,18 @@
         return mLastVisibility;
     }
 
-    void setAdjustedForIme(boolean adjusted, boolean animate, WindowState imeWin) {
-        if (mAdjustedForIme != adjusted) {
-            mAdjustedForIme = adjusted;
+    void setAdjustedForIme(
+            boolean adjustedForIme, boolean adjustedForDivider,
+            boolean animate, WindowState imeWin) {
+        if (mAdjustedForIme != adjustedForIme || mAdjustedForDivider != adjustedForDivider) {
             if (animate) {
-                startImeAdjustAnimation(adjusted, imeWin);
+                startImeAdjustAnimation(adjustedForIme, adjustedForDivider, imeWin);
             } else {
-
                 // Animation might be delayed, so only notify if we don't run an animation.
-                notifyAdjustedForImeChanged(adjusted, 0 /* duration */);
+                notifyAdjustedForImeChanged(adjustedForIme || adjustedForDivider, 0 /* duration */);
             }
+            mAdjustedForIme = adjustedForIme;
+            mAdjustedForDivider = adjustedForDivider;
         }
     }
 
@@ -346,7 +353,7 @@
             stack.getDimBounds(mTmpRect);
             if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
                 mDimLayer.setBounds(mTmpRect);
-                mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
+                mDimLayer.show(mService.mLayersController.getResizeDimLayer(),
                         alpha, 0 /* duration */);
             } else {
                 visibleAndValid = false;
@@ -457,11 +464,25 @@
         mAnimationTarget = to;
     }
 
-    private void startImeAdjustAnimation(boolean adjusted, WindowState imeWin) {
+    private void startImeAdjustAnimation(
+            boolean adjustedForIme, boolean adjustedForDivider, WindowState imeWin) {
         mAnimatingForIme = true;
         mAnimationStarted = false;
-        mAnimationStart = adjusted ? 0 : 1;
-        mAnimationTarget = adjusted ? 1 : 0;
+
+        // If we're not in an animation, the starting point depends on whether we're adjusted
+        // or not. If we're already in an animation, we start from where the current animation
+        // left off, so that the motion doesn't look discontinuous.
+        if (!mAnimatingForIme) {
+            mAnimationStart = mAdjustedForIme ? 1 : 0;
+            mDividerAnimationStart = mAdjustedForDivider ? 1 : 0;
+            mLastAnimationProgress = mAnimationStart;
+            mLastDividerProgress = mDividerAnimationStart;
+        } else {
+            mAnimationStart = mLastAnimationProgress;
+            mDividerAnimationStart = mLastDividerProgress;
+        }
+        mAnimationTarget = adjustedForIme ? 1 : 0;
+        mDividerAnimationTarget = adjustedForDivider ? 1 : 0;
 
         final ArrayList<TaskStack> stacks = mDisplayContent.getStacks();
         for (int i = stacks.size() - 1; i >= 0; --i) {
@@ -492,10 +513,12 @@
                 if (mDelayedImeWin != null) {
                     mDelayedImeWin.mWinAnimator.endDelayingAnimationStart();
                 }
-                notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+                notifyAdjustedForImeChanged(
+                        adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
             };
         } else {
-            notifyAdjustedForImeChanged(adjusted, IME_ADJUST_ANIM_DURATION);
+            notifyAdjustedForImeChanged(
+                    adjustedForIme || adjustedForDivider, IME_ADJUST_ANIM_DURATION);
         }
     }
 
@@ -515,11 +538,17 @@
     }
 
     public boolean animate(long now) {
+        if (mWindow == null) {
+            return false;
+        }
         if (mAnimatingForMinimizedDockedStack) {
             return animateForMinimizedDockedStack(now);
         } else if (mAnimatingForIme) {
             return animateForIme(now);
         } else {
+            if (mDimLayer != null && mDimLayer.isDimming()) {
+                mDimLayer.setLayer(mService.mLayersController.getResizeDimLayer());
+            }
             return false;
         }
     }
@@ -539,11 +568,15 @@
         for (int i = stacks.size() - 1; i >= 0; --i) {
             final TaskStack stack = stacks.get(i);
             if (stack != null && stack.isAdjustedForIme()) {
-                if (t >= 1f && mAnimationTarget == 0f) {
+                if (t >= 1f && mAnimationTarget == 0f && mDividerAnimationTarget == 0f) {
                     stack.resetAdjustedForIme(true /* adjustBoundsNow */);
                     updated = true;
                 } else {
-                    updated |= stack.updateAdjustForIme(getInterpolatedAnimationValue(t),
+                    mLastAnimationProgress = getInterpolatedAnimationValue(t);
+                    mLastDividerProgress = getInterpolatedDividerValue(t);
+                    updated |= stack.updateAdjustForIme(
+                            mLastAnimationProgress,
+                            mLastDividerProgress,
                             false /* force */);
                 }
                 if (t >= 1f) {
@@ -555,6 +588,8 @@
             mService.mWindowPlacerLocked.performSurfacePlacement();
         }
         if (t >= 1.0f) {
+            mLastAnimationProgress = mAnimationTarget;
+            mLastDividerProgress = mDividerAnimationTarget;
             mAnimatingForIme = false;
             return false;
         } else {
@@ -596,6 +631,10 @@
         return t * mAnimationTarget + (1 - t) * mAnimationStart;
     }
 
+    private float getInterpolatedDividerValue(float t) {
+        return t * mDividerAnimationTarget + (1 - t) * mDividerAnimationStart;
+    }
+
     /**
      * Gets the amount how much to minimize a stack depending on the interpolated fraction t.
      */
diff --git a/services/core/java/com/android/server/wm/DropPermissionsHandler.java b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
similarity index 91%
rename from services/core/java/com/android/server/wm/DropPermissionsHandler.java
rename to services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
index 5889fb8..1831ff9 100644
--- a/services/core/java/com/android/server/wm/DropPermissionsHandler.java
+++ b/services/core/java/com/android/server/wm/DragAndDropPermissionsHandler.java
@@ -23,11 +23,12 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 
-import com.android.internal.view.IDropPermissions;
+import com.android.internal.view.IDragAndDropPermissions;
 
 import java.util.ArrayList;
 
-class DropPermissionsHandler extends IDropPermissions.Stub implements IBinder.DeathRecipient {
+class DragAndDropPermissionsHandler extends IDragAndDropPermissions.Stub
+        implements IBinder.DeathRecipient {
 
     private final int mSourceUid;
     private final String mTargetPackage;
@@ -40,8 +41,8 @@
     private IBinder mActivityToken = null;
     private IBinder mPermissionOwnerToken = null;
 
-    DropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
-            int sourceUserId, int targetUserId) {
+    DragAndDropPermissionsHandler(ClipData clipData, int sourceUid, String targetPackage, int mode,
+                                  int sourceUserId, int targetUserId) {
         mSourceUid = sourceUid;
         mTargetPackage = targetPackage;
         mMode = mode;
diff --git a/services/core/java/com/android/server/wm/DragState.java b/services/core/java/com/android/server/wm/DragState.java
index ffe0336..0539b05 100644
--- a/services/core/java/com/android/server/wm/DragState.java
+++ b/services/core/java/com/android/server/wm/DragState.java
@@ -59,7 +59,7 @@
 import com.android.server.wm.WindowManagerService.DragInputEventReceiver;
 import com.android.server.wm.WindowManagerService.H;
 
-import com.android.internal.view.IDropPermissions;
+import com.android.internal.view.IDragAndDropPermissions;
 
 import java.util.ArrayList;
 
@@ -484,10 +484,10 @@
 
         final int targetUserId = UserHandle.getUserId(touchedWin.getOwningUid());
 
-        DropPermissionsHandler dropPermissions = null;
+        DragAndDropPermissionsHandler dragAndDropPermissions = null;
         if ((mFlags & View.DRAG_FLAG_GLOBAL) != 0 &&
                 (mFlags & DRAG_FLAGS_URI_ACCESS) != 0) {
-            dropPermissions = new DropPermissionsHandler(
+            dragAndDropPermissions = new DragAndDropPermissionsHandler(
                     mData,
                     mUid,
                     touchedWin.getOwningPackage(),
@@ -501,7 +501,7 @@
         final int myPid = Process.myPid();
         final IBinder token = touchedWin.mClient.asBinder();
         DragEvent evt = obtainDragEvent(touchedWin, DragEvent.ACTION_DROP, x, y,
-                null, null, mData, dropPermissions, false);
+                null, null, mData, dragAndDropPermissions, false);
         try {
             touchedWin.mClient.dispatchDragEvent(evt);
 
@@ -524,12 +524,12 @@
     private static DragEvent obtainDragEvent(WindowState win, int action,
             float x, float y, Object localState,
             ClipDescription description, ClipData data,
-            IDropPermissions dropPermissions,
+            IDragAndDropPermissions dragAndDropPermissions,
             boolean result) {
         final float winX = win.translateToWindowX(x);
         final float winY = win.translateToWindowY(y);
         return DragEvent.obtain(action, winX, winY, localState, description, data,
-                dropPermissions, result);
+                dragAndDropPermissions, result);
     }
 
     boolean stepAnimationLocked(long currentTimeMs) {
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 4f49eed..6925fa5 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -601,7 +601,7 @@
                     // Anyway we don't need to synchronize position and content updates for these
                     // windows since they aren't at the base layer and could be moved around anyway.
                     if (!win.computeDragResizing() && win.mAttrs.type == TYPE_BASE_APPLICATION &&
-                            !mStack.getBoundsAnimating()) {
+                            !mStack.getBoundsAnimating() && !win.isGoneForLayoutLw()) {
                         win.mResizedWhileNotDragResizing = true;
                     }
                 }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 1fd2b1f..037f316 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -41,7 +41,6 @@
 import android.util.SparseArray;
 import android.view.DisplayInfo;
 import android.view.Surface;
-import android.view.animation.PathInterpolator;
 import android.view.SurfaceControl;
 
 import com.android.internal.policy.DividerSnapAlgorithm;
@@ -119,13 +118,13 @@
     // Whether the stack and all its tasks is currently being drag-resized
     private boolean mDragResizing;
 
-    private final Rect mLastContentBounds = new Rect();
     private final Rect mTmpAdjustedBounds = new Rect();
     private boolean mAdjustedForIme;
     private boolean mImeGoingAway;
     private WindowState mImeWin;
     private float mMinimizeAmount;
     private float mAdjustImeAmount;
+    private float mAdjustDividerAmount;
     private final int mDockedStackMinimizeThickness;
 
     // If this is true, we are in the bounds animating mode.
@@ -502,7 +501,7 @@
                 final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
                 for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
                     final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-                    if (winAnimator.isAnimating() || winAnimator.mWin.mAnimatingExit) {
+                    if (winAnimator.isAnimationSet() || winAnimator.mWin.mAnimatingExit) {
                         return true;
                     }
                 }
@@ -555,6 +554,15 @@
         if (toTop) {
             mDisplayContent.moveStack(this, true);
         }
+
+        if (StackId.windowsAreScaleable(mStackId)) {
+            // We force windows out of SCALING_MODE_FREEZE
+            // so that we can continue to animate them
+            // while a resize is pending.
+            forceWindowsScaleable(task, true);
+        } else {
+            forceWindowsScaleable(task, false);
+        }
         EventLog.writeEvent(EventLogTags.WM_TASK_MOVED, task.mTaskId, toTop ? 1 : 0, position);
     }
 
@@ -645,9 +653,12 @@
         Rect bounds = null;
         final TaskStack dockedStack = mService.mStackIdToStack.get(DOCKED_STACK_ID);
         if (mStackId == DOCKED_STACK_ID
-                || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId))) {
+                || (dockedStack != null && StackId.isResizeableByDockedStack(mStackId)
+                        && !dockedStack.isFullscreen())) {
             // The existence of a docked stack affects the size of other static stack created since
-            // the docked stack occupies a dedicated region on screen.
+            // the docked stack occupies a dedicated region on screen, but only if the dock stack is
+            // not fullscreen. If it's fullscreen, it means that we are in the transition of
+            // dismissing it, so we must not resize this stack.
             bounds = new Rect();
             displayContent.getLogicalDisplayRect(mTmpRect);
             mTmpRect2.setEmpty();
@@ -853,7 +864,8 @@
         if (!mAdjustedForIme) {
             mAdjustedForIme = true;
             mAdjustImeAmount = 0f;
-            updateAdjustForIme(0f, true /* force */);
+            mAdjustDividerAmount = 0f;
+            updateAdjustForIme(0f, 0f, true /* force */);
         }
     }
 
@@ -873,9 +885,11 @@
      *
      * @return true if a traversal should be performed after the adjustment.
      */
-    boolean updateAdjustForIme(float adjustAmount, boolean force) {
-        if (adjustAmount != mAdjustImeAmount || force) {
+    boolean updateAdjustForIme(float adjustAmount, float adjustDividerAmount, boolean force) {
+        if (adjustAmount != mAdjustImeAmount
+                || adjustDividerAmount != mAdjustDividerAmount || force) {
             mAdjustImeAmount = adjustAmount;
+            mAdjustDividerAmount = adjustDividerAmount;
             updateAdjustedBounds();
             return isVisibleForUserLocked();
         } else {
@@ -895,6 +909,7 @@
             mAdjustedForIme = false;
             mImeGoingAway = false;
             mAdjustImeAmount = 0f;
+            mAdjustDividerAmount = 0f;
             updateAdjustedBounds();
             mService.setResizeDimLayer(false, mStackId, 1.0f);
         } else {
@@ -970,7 +985,6 @@
             contentBounds.bottom = imeTop;
         }
 
-        mLastContentBounds.set(contentBounds);
         final int yOffset = displayContentRect.bottom - contentBounds.bottom;
 
         final int dividerWidth =
@@ -992,25 +1006,27 @@
                     (int) (mAdjustImeAmount * bottom + (1 - mAdjustImeAmount) * mBounds.bottom);
             mFullyAdjustedImeBounds.set(mBounds);
         } else {
-            final int top;
-            final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
-            if (isFocusedStack) {
-                // If this stack is docked on bottom and has focus, we shift it up so that it's not
-                // occluded by IME. We try to move it up by the height of the IME window, but only
-                // to the extent that leaves at least 30% of the top stack visible.
-                final int minTopStackBottom =
-                        getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
-                top = Math.max(
-                        mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
-            } else {
-                // If this stack is docked on bottom but doesn't have focus, we don't need to adjust
-                // for IME, but still need to apply a small adjustment due to the thinner divider.
-                top = mBounds.top - dividerWidth + dividerWidthInactive;
-            }
+            // When the stack is on bottom and has no focus, it's only adjusted for divider width.
+            final int dividerWidthDelta = dividerWidthInactive - dividerWidth;
+
+            // When the stack is on bottom and has focus, it needs to be moved up so as to
+            // not occluded by IME, and at the same time adjusted for divider width.
+            // We try to move it up by the height of the IME window, but only to the extent
+            // that leaves at least 30% of the top stack visible.
+            // 'top' is where the top of bottom stack will move to in this case.
+            final int topBeforeImeAdjust = mBounds.top - dividerWidth + dividerWidthInactive;
+            final int minTopStackBottom =
+                    getMinTopStackBottom(displayContentRect, mBounds.top - dividerWidth);
+            final int top = Math.max(
+                    mBounds.top - yOffset, minTopStackBottom + dividerWidthInactive);
 
             mTmpAdjustedBounds.set(mBounds);
-            mTmpAdjustedBounds.top =
-                    (int) (mAdjustImeAmount * top + (1 - mAdjustImeAmount) * mBounds.top);
+            // Account for the adjustment for IME and divider width separately.
+            // (top - topBeforeImeAdjust) is the amount of movement due to IME only,
+            // and dividerWidthDelta is due to divider width change only.
+            mTmpAdjustedBounds.top = mBounds.top +
+                    (int) (mAdjustImeAmount * (top - topBeforeImeAdjust) +
+                            mAdjustDividerAmount * dividerWidthDelta);
             mFullyAdjustedImeBounds.set(mBounds);
             mFullyAdjustedImeBounds.top = top;
             mFullyAdjustedImeBounds.bottom = top + mBounds.height();
@@ -1078,13 +1094,13 @@
         }
         if (!adjust) {
             mTmpAdjustedBounds.setEmpty();
-            mLastContentBounds.setEmpty();
         }
         setAdjustedBounds(mTmpAdjustedBounds);
 
-        final boolean isFocusedStack = mService.getFocusedStackLocked() == this;
-        if (mAdjustedForIme && adjust && !isFocusedStack) {
-            final float alpha = mAdjustImeAmount * IME_ADJUST_DIM_AMOUNT;
+        final boolean isImeTarget = (mService.getImeTargetStackLocked() == this);
+        if (mAdjustedForIme && adjust && !isImeTarget) {
+            final float alpha = Math.max(mAdjustImeAmount, mAdjustDividerAmount)
+                    * IME_ADJUST_DIM_AMOUNT;
             mService.setResizeDimLayer(true, mStackId, alpha);
         }
     }
@@ -1272,20 +1288,18 @@
         return true;
     }
 
-    void forceWindowsScaleable(boolean force) {
+    void forceWindowsScaleable(Task task, boolean force) {
         SurfaceControl.openTransaction();
         try {
-            for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
-                final ArrayList<AppWindowToken> activities = mTasks.get(taskNdx).mAppTokens;
-                for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
-                    final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
-                    for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
-                        final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
-                        if (winAnimator == null || !winAnimator.hasSurface()) {
-                            continue;
-                        }
-                        winAnimator.mSurfaceController.forceScaleableInTransaction(force);
+            final ArrayList<AppWindowToken> activities = task.mAppTokens;
+            for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
+                final ArrayList<WindowState> windows = activities.get(activityNdx).allAppWindows;
+                for (int winNdx = windows.size() - 1; winNdx >= 0; --winNdx) {
+                    final WindowStateAnimator winAnimator = windows.get(winNdx).mWinAnimator;
+                    if (winAnimator == null || !winAnimator.hasSurface()) {
+                        continue;
                     }
+                    winAnimator.mSurfaceController.forceScaleableInTransaction(force);
                 }
             }
         } finally {
@@ -1296,10 +1310,6 @@
     @Override  // AnimatesBounds
     public void onAnimationStart() {
         synchronized (mService.mWindowMap) {
-            // We force windows out of SCALING_MODE_FREEZE
-            // so that we can continue to animate them
-            // while a resize is pending.
-            forceWindowsScaleable(true);
             mFreezeMovementAnimations = true;
             mBoundsAnimating = true;
         }
@@ -1310,7 +1320,6 @@
         synchronized (mService.mWindowMap) {
             mFreezeMovementAnimations = false;
             mBoundsAnimating = false;
-            forceWindowsScaleable(false);
             mService.requestTraversal();
         }
         if (mStackId == PINNED_STACK_ID) {
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index e44b0f3..88028be 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -146,7 +146,7 @@
     }
 
     boolean isWallpaperTargetAnimating() {
-        return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimating()
+        return mWallpaperTarget != null && mWallpaperTarget.mWinAnimator.isAnimationSet()
                 && !mWallpaperTarget.mWinAnimator.isDummyAnimation();
     }
 
@@ -516,7 +516,7 @@
             if (hasWallpaper && w.isOnScreen() && (mWallpaperTarget == w || w.isDrawFinishedLw())) {
                 if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: #" + i + "=" + w);
                 result.setWallpaperTarget(w, i);
-                if (w == mWallpaperTarget && w.mWinAnimator.isAnimating()) {
+                if (w == mWallpaperTarget && w.mWinAnimator.isAnimationSet()) {
                     // The current wallpaper target is animating, so we'll look behind it for
                     // another possible target and figure out what is going on later.
                     if (DEBUG_WALLPAPER) Slog.v(TAG,
diff --git a/services/core/java/com/android/server/wm/WindowAnimator.java b/services/core/java/com/android/server/wm/WindowAnimator.java
index 6bc633f..eae7838 100644
--- a/services/core/java/com/android/server/wm/WindowAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowAnimator.java
@@ -670,6 +670,7 @@
         if (SHOW_TRANSACTIONS) Slog.i(
                 TAG, ">>> OPEN TRANSACTION animateLocked");
         SurfaceControl.openTransaction();
+        SurfaceControl.setAnimationTransaction();
         try {
             final int numDisplays = mDisplayContentsAnimators.size();
             for (int i = 0; i < numDisplays; i++) {
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 8608967..072e10f 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -27,6 +27,7 @@
 import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.LAYER_OFFSET_DIM;
 import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
 
 /**
@@ -150,7 +151,7 @@
      *         above all application surfaces.
      */
     int getResizeDimLayer() {
-        return mDockDivider.mLayer - 1;
+        return (mDockDivider != null) ? mDockDivider.mLayer - 1 : LAYER_OFFSET_DIM;
     }
 
     private void logDebugLayers(WindowList windows) {
@@ -208,7 +209,11 @@
 
         if (mDockDivider != null && mDockDivider.isVisibleLw()) {
             while (!mInputMethodWindows.isEmpty()) {
-                layer = assignAndIncreaseLayerIfNeeded(mInputMethodWindows.remove(), layer);
+                final WindowState w = mInputMethodWindows.remove();
+                // Only ever move IME windows up, else we brake IME for windows above the divider.
+                if (layer > w.mLayer) {
+                    layer = assignAndIncreaseLayerIfNeeded(w, layer);
+                }
             }
         }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 38f12a1..0b66959 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -120,7 +120,6 @@
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.inputmethod.InputMethodManagerInternal;
-import android.widget.Toast;
 
 import com.android.internal.R;
 import com.android.internal.app.IAssistScreenshotReceiver;
@@ -174,6 +173,7 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.DOCKED_TOP;
 import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
 import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
 import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
@@ -846,6 +846,13 @@
     // since they won't be notified through the app window animator.
     final List<IBinder> mNoAnimationNotifyOnTransitionFinished = new ArrayList<>();
 
+    // List of displays to reconfigure after configuration changes.
+    // Some of the information reported for a display is dependent on resources to do the right
+    // calculations. For example, {@link DisplayInfo#smallestNominalAppWidth} and company are
+    // dependent on the height and width of the status and nav bar which change depending on the
+    // current configuration.
+    private final DisplayContentList mReconfigureOnConfigurationChanged = new DisplayContentList();
+
     /** Listener to notify activity manager about app transitions. */
     private final WindowManagerInternal.AppTransitionListener mActivityManagerAppTransitionNotifier
             = new WindowManagerInternal.AppTransitionListener() {
@@ -1525,7 +1532,7 @@
 
                 if (highestTarget != null) {
                     if (DEBUG_INPUT_METHOD) Slog.v(TAG_WM, mAppTransition + " " + highestTarget
-                            + " animating=" + highestTarget.mWinAnimator.isAnimating()
+                            + " animating=" + highestTarget.mWinAnimator.isAnimationSet()
                             + " layer=" + highestTarget.mWinAnimator.mAnimLayer
                             + " new layer=" + w.mWinAnimator.mAnimLayer);
 
@@ -1535,7 +1542,7 @@
                         mInputMethodTargetWaitingAnim = true;
                         mInputMethodTarget = highestTarget;
                         return highestPos + 1;
-                    } else if (highestTarget.mWinAnimator.isAnimating() &&
+                    } else if (highestTarget.mWinAnimator.isAnimationSet() &&
                             highestTarget.mWinAnimator.mAnimLayer > w.mWinAnimator.mAnimLayer) {
                         // If the window we are currently targeting is involved
                         // with an animation, and it is on top of the next target
@@ -1567,11 +1574,13 @@
             // If the docked divider is visible, we still need to go through this whole
             // excercise to find the appropriate input method target (used for animations
             // and dialog adjustments), but for purposes of Z ordering we simply wish to
-            // place it above the docked divider.
+            // place it above the docked divider. Unless it is already above the divider.
             WindowState dockedDivider = w.mDisplayContent.mDividerControllerLocked.getWindow();
             if (dockedDivider != null && dockedDivider.isVisibleLw()) {
                 int dividerIndex = windows.indexOf(dockedDivider);
-                return dividerIndex > 0 ? dividerIndex + 1 : i + 1;
+                if (dividerIndex > 0 && dividerIndex > i) {
+                    return dividerIndex + 1;
+                }
             }
             return i+1;
         }
@@ -1805,6 +1814,16 @@
         return true;
     }
 
+    private static boolean excludeWindowTypeFromTapOutTask(int windowType) {
+        switch (windowType) {
+            case TYPE_STATUS_BAR:
+            case TYPE_NAVIGATION_BAR:
+            case TYPE_INPUT_METHOD_DIALOG:
+                return true;
+        }
+        return false;
+    }
+
     public int addWindow(Session session, IWindow client, int seq,
             WindowManager.LayoutParams attrs, int viewVisibility, int displayId,
             Rect outContentInsets, Rect outStableInsets, Rect outOutsets,
@@ -2003,7 +2022,7 @@
 
             res = WindowManagerGlobal.ADD_OKAY;
 
-            if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+            if (excludeWindowTypeFromTapOutTask(type)) {
                 displayContent.mTapExcludedWindows.add(win);
             }
 
@@ -2265,7 +2284,7 @@
                 + " mRemoveOnExit=" + win.mRemoveOnExit
                 + " mHasSurface=" + win.mHasSurface
                 + " surfaceShowing=" + win.mWinAnimator.getShown()
-                + " isAnimating=" + win.mWinAnimator.isAnimating()
+                + " isAnimationSet=" + win.mWinAnimator.isAnimationSet()
                 + " app-animation="
                 + (win.mAppToken != null ? win.mAppToken.mAppAnimator.animation : null)
                 + " mWillReplaceWindow=" + win.mWillReplaceWindow
@@ -2329,7 +2348,7 @@
                 }
             }
             final boolean isAnimating =
-                    winAnimator.isAnimating() && !winAnimator.isDummyAnimation();
+                    winAnimator.isAnimationSet() && !winAnimator.isDummyAnimation();
             final boolean lastWindowIsStartingWindow = startingWindow && appToken != null
                     && appToken.allAppWindows.size() == 1;
             // We delay the removal of a window if it has a showing surface that can be used to run
@@ -2395,7 +2414,7 @@
         }
 
         final int type = win.mAttrs.type;
-        if (type == TYPE_STATUS_BAR || type == TYPE_NAVIGATION_BAR) {
+        if (excludeWindowTypeFromTapOutTask(type)) {
             final DisplayContent displaycontent = win.getDisplayContent();
             displaycontent.mTapExcludedWindows.remove(win);
         }
@@ -2914,7 +2933,7 @@
             focusMayChange = isDefaultDisplay;
             win.mAnimatingExit = true;
             win.mWinAnimator.mAnimating = true;
-        } else if (win.mWinAnimator.isAnimating()) {
+        } else if (win.mWinAnimator.isAnimationSet()) {
             // Currently in a hide animation... turn this into
             // an exit.
             win.mAnimatingExit = true;
@@ -3271,7 +3290,7 @@
                         WindowState win = wtoken.windows.get(i);
                         displayContent = win.getDisplayContent();
 
-                        if (win.mWinAnimator.isAnimating()) {
+                        if (win.mWinAnimator.isAnimationSet()) {
                             delayed = true;
                         }
 
@@ -3684,7 +3703,19 @@
 
     private int[] onConfigurationChanged() {
         mPolicy.onConfigurationChanged();
-        getDefaultDisplayContentLocked().getDockedDividerController().onConfigurationChanged();
+
+        final DisplayContent defaultDisplayContent = getDefaultDisplayContentLocked();
+        if (!mReconfigureOnConfigurationChanged.contains(defaultDisplayContent)) {
+            // The default display size information is heavily dependent on the resources in the
+            // current configuration, so we need to reconfigure it everytime the configuration
+            // changes. See {@link PhoneWindowManager#setInitialDisplaySize}...sigh...
+            mReconfigureOnConfigurationChanged.add(defaultDisplayContent);
+        }
+        for (int i = mReconfigureOnConfigurationChanged.size() - 1; i >= 0; i--) {
+            reconfigureDisplayLocked(mReconfigureOnConfigurationChanged.remove(i));
+        }
+
+        defaultDisplayContent.getDockedDividerController().onConfigurationChanged();
         mChangedStackList.clear();
         for (int stackNdx = mStackIdToStack.size() - 1; stackNdx >= 0; stackNdx--) {
             final TaskStack stack = mStackIdToStack.valueAt(stackNdx);
@@ -4248,7 +4279,6 @@
                                     WindowManagerPolicy.TRANSIT_EXIT);
                         }
                     }
-                    win.mAnimatingExit = true;
                     changed = true;
                     win.setDisplayLayoutNeeded();
                 }
@@ -4288,7 +4318,7 @@
         }
 
         for (int i = wtoken.allAppWindows.size() - 1; i >= 0 && !delayed; i--) {
-            if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimating()) {
+            if (wtoken.allAppWindows.get(i).mWinAnimator.isWindowAnimationSet()) {
                 delayed = true;
             }
         }
@@ -7455,27 +7485,41 @@
 
     void adjustForImeIfNeeded(final DisplayContent displayContent) {
         final WindowState imeWin = mInputMethodWindow;
-        final TaskStack focusedStack = getFocusedStackLocked();
+        final boolean imeVisible = imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw();
         final boolean dockVisible = isStackVisibleLocked(DOCKED_STACK_ID);
-        if (imeWin != null && imeWin.isVisibleLw() && imeWin.isDisplayedLw()
-                && dockVisible && focusedStack != null) {
-            final boolean isFocusOnBottom = focusedStack.getDockSide() == DOCKED_BOTTOM;
+        final TaskStack imeTargetStack = getImeTargetStackLocked();
+        final int imeDockSide = (dockVisible && imeTargetStack != null) ?
+                imeTargetStack.getDockSide() : DOCKED_INVALID;
+        final boolean imeOnTop = (imeDockSide == DOCKED_TOP);
+        final boolean imeOnBottom = (imeDockSide == DOCKED_BOTTOM);
+
+        // The divider could be adjusted for IME position, or be thinner than usual,
+        // or both. There are three possible cases:
+        // - If IME is visible, and focus is on top, divider is not moved for IME but thinner.
+        // - If IME is visible, and focus is on bottom, divider is moved for IME and thinner.
+        // - If IME is not visible, divider is not moved and is normal width.
+
+        if (imeVisible && dockVisible && (imeOnTop || imeOnBottom)) {
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
                 final boolean isDockedOnBottom = stack.getDockSide() == DOCKED_BOTTOM;
-                if (stack.isVisibleLocked() && (isFocusOnBottom || isDockedOnBottom)) {
+                if (stack.isVisibleLocked() && (imeOnBottom || isDockedOnBottom)) {
                     stack.setAdjustedForIme(imeWin);
+                } else {
+                    stack.resetAdjustedForIme(false);
                 }
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(true, true, imeWin);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(
+                    imeOnBottom /*ime*/, true /*divider*/, true /*animate*/, imeWin);
         } else {
             final ArrayList<TaskStack> stacks = displayContent.getStacks();
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 final TaskStack stack = stacks.get(i);
                 stack.resetAdjustedForIme(!dockVisible);
             }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(false, dockVisible, imeWin);
+            displayContent.mDividerControllerLocked.setAdjustedForIme(
+                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin);
         }
     }
 
@@ -7608,8 +7652,10 @@
         return mCurrentFocus;
     }
 
-    TaskStack getFocusedStackLocked() {
-        return mCurrentFocus != null ? mCurrentFocus.getStack() : null;
+    TaskStack getImeTargetStackLocked() {
+        // Don't use WindowState.getStack() because it returns home stack for system windows.
+        Task imeTask = mInputMethodTarget != null ? mInputMethodTarget.getTask() : null;
+        return imeTask != null ? imeTask.mStack : null;
     }
 
     private void showAuditSafeModeNotification() {
@@ -8827,6 +8873,9 @@
             mWaitingForConfig = true;
             startFreezingDisplayLocked(false, 0, 0);
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+            if (!mReconfigureOnConfigurationChanged.contains(displayContent)) {
+                mReconfigureOnConfigurationChanged.add(displayContent);
+            }
         }
 
         mWindowPlacerLocked.performSurfacePlacement();
@@ -9079,7 +9128,7 @@
 
     void updateResizingWindows(final WindowState w) {
         final WindowStateAnimator winAnimator = w.mWinAnimator;
-        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq) {
+        if (w.mHasSurface && w.mLayoutSeq == mLayoutSeq && !w.isGoneForLayoutLw()) {
             w.setInsetsChanged();
             boolean configChanged = w.isConfigChanged();
             if (DEBUG_CONFIGURATION && configChanged) {
@@ -9112,7 +9161,8 @@
                             + " " + w.mOutsets.toShortString()
                             + " surfaceResized=" + winAnimator.mSurfaceResized
                             + " configChanged=" + configChanged
-                            + " dragResizingChanged=" + dragResizingChanged);
+                            + " dragResizingChanged=" + dragResizingChanged
+                            + " resizedWhileNotDragResizing=" + w.mResizedWhileNotDragResizing);
                 }
 
                 // If it's a dead window left on screen, and the configuration changed,
@@ -9354,7 +9404,6 @@
         WindowState newFocus = computeFocusedWindowLocked();
         if (mCurrentFocus != newFocus) {
             Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmUpdateFocus");
-            TaskStack oldFocusedStack = getFocusedStackLocked();
             // This check makes sure that we don't already have the focus
             // change message pending.
             mH.removeMessages(H.REPORT_FOCUS_CHANGE);
@@ -9376,7 +9425,6 @@
             mLosingFocus.remove(newFocus);
 
             int focusChanged = mPolicy.focusChangedLw(oldFocus, newFocus);
-            TaskStack newFocusedStack = getFocusedStackLocked();
 
             if (imWindowChanged && oldFocus != mInputMethodWindow) {
                 // Focus of the input method window changed. Perform layout if needed.
@@ -9406,18 +9454,6 @@
                 mInputMonitor.setInputFocusLw(mCurrentFocus, updateInputWindows);
             }
 
-            // TODO: Reset and re-apply IME adjustment if needed when stack focus changed.
-            // This makes sure divider starts an animation from pre-adjust position to final
-            // position. Ideally we want to skip the reset and animation from current position
-            // directly to final position.
-            final WindowState imeWin = mInputMethodWindow;
-            if (oldFocusedStack != null) {
-                oldFocusedStack.resetAdjustedForIme(true);
-            }
-            if (newFocusedStack != null) {
-                newFocusedStack.resetAdjustedForIme(true);
-            }
-            displayContent.mDividerControllerLocked.setAdjustedForIme(false, false, imeWin);
             adjustForImeIfNeeded(displayContent);
 
             Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 76fdda01..2c5b035 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2266,9 +2266,11 @@
     private void dispatchResized(Rect frame, Rect overscanInsets, Rect contentInsets,
             Rect visibleInsets, Rect stableInsets, Rect outsets, boolean reportDraw,
             Configuration newConfig) throws RemoteException {
+        final boolean forceRelayout = isDragResizeChanged() || mResizedWhileNotDragResizing;
+
         mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
                 reportDraw, newConfig, getBackdropFrame(frame),
-                isDragResizeChanged() /* forceRelayout */, mPolicy.isNavBarForcedShownLw(this));
+                forceRelayout, mPolicy.isNavBarForcedShownLw(this));
         mDragResizingChangeReported = true;
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 8c29c9b..1493bc7 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.ActivityManager.StackId;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -291,21 +292,33 @@
         }
     }
 
-    /** Is the window or its container currently animating? */
-    boolean isAnimating() {
+    /**
+     * Is the window or its container currently set to animate or currently animating?
+     */
+    boolean isAnimationSet() {
         return mAnimation != null
                 || (mAttachedWinAnimator != null && mAttachedWinAnimator.mAnimation != null)
                 || (mAppAnimator != null && mAppAnimator.isAnimating());
     }
 
+    /**
+     * @return whether an animation is about to start, i.e. the animation is set already but we
+     *         haven't processed the first frame yet.
+     */
+    boolean isAnimationStarting() {
+        return isAnimationSet() && !mAnimating;
+    }
+
     /** Is the window animating the DummyAnimation? */
     boolean isDummyAnimation() {
         return mAppAnimator != null
                 && mAppAnimator.animation == sDummyAnimation;
     }
 
-    /** Is this window currently set to animate or currently animating? */
-    boolean isWindowAnimating() {
+    /**
+     * Is this window currently set to animate or currently animating?
+     */
+    boolean isWindowAnimationSet() {
         return mAnimation != null;
     }
 
@@ -340,7 +353,7 @@
     // there is more animation to run.
     boolean stepAnimationLocked(long currentTime) {
         // Save the animation state as it was before this step so WindowManagerService can tell if
-        // we just started or just stopped animating by comparing mWasAnimating with isAnimating().
+        // we just started or just stopped animating by comparing mWasAnimating with isAnimationSet().
         mWasAnimating = mAnimating;
         final DisplayContent displayContent = mWin.getDisplayContent();
         if (displayContent != null && mService.okToDisplay()) {
@@ -402,7 +415,7 @@
                 // Little trick to get through the path below to act like
                 // we have finished an animation.
                 mAnimating = true;
-            } else if (isAnimating()) {
+            } else if (isAnimationSet()) {
                 mAnimating = true;
             }
         } else if (mAnimation != null) {
@@ -476,7 +489,7 @@
                 TAG, "finishExit in " + this
                 + ": exiting=" + mWin.mAnimatingExit
                 + " remove=" + mWin.mRemoveOnExit
-                + " windowAnimating=" + isWindowAnimating());
+                + " windowAnimating=" + isWindowAnimationSet());
 
         if (!mWin.mChildWindows.isEmpty()) {
             // Copying to a different list as multiple children can be removed.
@@ -499,7 +512,7 @@
             }
         }
 
-        if (!isWindowAnimating()) {
+        if (!isWindowAnimationSet()) {
             //TODO (multidisplay): Accessibility is supported only for the default display.
             if (mService.mAccessibilityController != null
                     && mWin.getDisplayId() == DEFAULT_DISPLAY) {
@@ -511,7 +524,7 @@
             return;
         }
 
-        if (isWindowAnimating()) {
+        if (isWindowAnimationSet()) {
             return;
         }
 
@@ -1310,7 +1323,7 @@
         final int stackClip = resolveStackClip();
 
         // It's animating and we don't want to clip it to stack bounds during animation - abort.
-        if (isAnimating() && stackClip == STACK_CLIP_NONE) {
+        if (isAnimationSet() && stackClip == STACK_CLIP_NONE) {
             return;
         }
 
@@ -1332,7 +1345,7 @@
 
         // If we are animating, we either apply the clip before applying all the animation
         // transformation or after all the transformation.
-        final boolean useFinalClipRect = isAnimating() && stackClip == STACK_CLIP_AFTER_ANIM;
+        final boolean useFinalClipRect = isAnimationSet() && stackClip == STACK_CLIP_AFTER_ANIM;
 
         // We need to do some acrobatics with surface position, because their clip region is
         // relative to the inside of the surface, but the stack bounds aren't.
@@ -1507,7 +1520,7 @@
                 w.mToken.hasVisible = true;
             }
         } else {
-            if (DEBUG_ANIM && isAnimating()) {
+            if (DEBUG_ANIM && isAnimationSet()) {
                 Slog.v(TAG, "prepareSurface: No changes in animation for " + this);
             }
             displayed = true;
@@ -1683,6 +1696,11 @@
      * @return Returns true if the surface was successfully shown.
      */
     private boolean showSurfaceRobustlyLocked() {
+        final Task task = mWin.getTask();
+        if (task != null && StackId.windowsAreScaleable(task.mStack.mStackId)) {
+            mSurfaceController.forceScaleableInTransaction(true);
+        }
+
         boolean shown = mSurfaceController.showRobustlyInTransaction();
         if (!shown)
             return false;
diff --git a/services/core/java/com/android/server/wm/WindowSurfaceController.java b/services/core/java/com/android/server/wm/WindowSurfaceController.java
index 6eed5e7..af47369 100644
--- a/services/core/java/com/android/server/wm/WindowSurfaceController.java
+++ b/services/core/java/com/android/server/wm/WindowSurfaceController.java
@@ -100,6 +100,8 @@
     void hideInTransaction(String reason) {
         if (SHOW_TRANSACTIONS) logSurface("HIDE ( " + reason + " )", null);
         mHiddenForOtherReasons = true;
+
+        mAnimator.destroyPreservedSurfaceLocked();
         updateVisibility();
     }
 
@@ -180,6 +182,7 @@
                 updateVisibility();
             } else {
                 mHiddenForCrop = true;
+                mAnimator.destroyPreservedSurfaceLocked();
                 updateVisibility();
             }
         } catch (RuntimeException e) {
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 928fcc0..8937f09 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -10,7 +10,6 @@
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
 import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_SUSTAINED_PERFORMANCE_MODE;
 import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
 import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
 import static android.view.WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG;
 import static android.view.WindowManager.LayoutParams.TYPE_SYSTEM_DIALOG;
@@ -762,13 +761,15 @@
                             }
                         }
                     }
-                    if (!winAnimator.isAnimating()) {
+                    if (!winAnimator.isAnimationStarting()) {
                         // Updates the shown frame before we set up the surface. This is needed
                         // because the resizing could change the top-left position (in addition to
                         // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
-                        // position the surface. We only apply it to windows that aren't animating,
-                        // because we depend on the animation to calculate the correct shown frame
-                        // on the next animation step.
+                        // position the surface.
+                        //
+                        // If an animation is being started, we can't call this method because the
+                        // animation hasn't processed its initial transformation yet, but in general
+                        // we do want to update the position if the window is animating.
                         winAnimator.computeShownFrameLocked();
                     }
                     winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
@@ -792,7 +793,7 @@
                         if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
                             Slog.v(TAG, "Eval win " + w + ": isDrawn="
                                     + w.isDrawnLw()
-                                    + ", isAnimating=" + winAnimator.isAnimating());
+                                    + ", isAnimationSet=" + winAnimator.isAnimationSet());
                             if (!w.isDrawnLw()) {
                                 Slog.v(TAG, "Not displayed: s="
                                         + winAnimator.mSurfaceController
@@ -943,7 +944,8 @@
             // windows, since that means "perform layout as normal,
             // just don't display").
             if (!gone || !win.mHaveFrame || win.mLayoutNeeded
-                    || ((win.isConfigChanged() || win.setInsetsChanged()) &&
+                    || ((win.isConfigChanged() || win.setInsetsChanged())
+                            && !win.isGoneForLayoutLw() &&
                             ((win.mAttrs.privateFlags & PRIVATE_FLAG_KEYGUARD) != 0 ||
                             (win.mHasSurface && win.mAppToken != null &&
                             win.mAppToken.layoutConfigChanges)))) {
diff --git a/services/core/jni/Android.mk b/services/core/jni/Android.mk
index 5e5c6d9..a502c3a 100644
--- a/services/core/jni/Android.mk
+++ b/services/core/jni/Android.mk
@@ -28,6 +28,7 @@
     $(LOCAL_REL_DIR)/com_android_server_power_PowerManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SerialService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_SystemServer.cpp \
+    $(LOCAL_REL_DIR)/com_android_server_tv_TvUinputBridge.cpp \
     $(LOCAL_REL_DIR)/com_android_server_tv_TvInputHal.cpp \
     $(LOCAL_REL_DIR)/com_android_server_vr_VrManagerService.cpp \
     $(LOCAL_REL_DIR)/com_android_server_UsbDeviceManager.cpp \
diff --git a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
index 774577d..8ea9bfc 100644
--- a/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
+++ b/services/core/jni/com_android_server_location_FlpHardwareProvider.cpp
@@ -661,6 +661,16 @@
     TranslateToObject(lastLocation, locationObject);
   }
 
+  // sCallbacksObject is created when FlpHardwareProvider on Java side is
+  // initialized. Sometimes the hardware may call this function before the Java
+  // side is ready. In order to prevent the system crash, check whether
+  // sCallbacksObj has been created. If not, simply ignore this event from
+  // hardware.
+  if (sCallbacksObj == NULL) {
+    ALOGE("FlpHardwareProvider hasn't been initialized.");
+    return;
+  }
+
   sCallbackEnv->CallVoidMethod(
       sCallbacksObj,
       sOnGeofenceMonitorStatus,
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 058b631..c5c90e0 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1194,7 +1194,7 @@
     JavaObject object(env, "android/location/GnssMeasurement");
     GpsMeasurementFlags flags = measurement->flags;
     SET(Svid, static_cast<int32_t>(measurement->prn));
-    if (measurement->prn >= 1 || measurement->prn <= 32) {
+    if (measurement->prn >= 1 && measurement->prn <= 32) {
         SET(ConstellationType, static_cast<int32_t>(GNSS_CONSTELLATION_GPS));
     } else {
         ALOGD("Unknown constellation type with Svid = %d.", measurement->prn);
diff --git a/services/core/jni/com_android_server_tv_TvKeys.h b/services/core/jni/com_android_server_tv_TvKeys.h
new file mode 100644
index 0000000..4895f34
--- /dev/null
+++ b/services/core/jni/com_android_server_tv_TvKeys.h
@@ -0,0 +1,113 @@
+#ifndef ANDROIDTVREMOTE_SERVICE_JNI_KEYS_H_
+#define ANDROIDTVREMOTE_SERVICE_JNI_KEYS_H_
+
+#include <android/keycodes.h>
+#include <linux/input.h>
+
+namespace android {
+
+// Map the keys specified in virtual-remote.kl.
+// Only specify the keys actually used in the layout here.
+struct Key {
+    int linuxKeyCode;
+    int32_t androidKeyCode;
+};
+
+// List of all of the keycodes that the emote is capable of sending.
+static Key KEYS[] = {
+    // Volume Control
+    { KEY_VOLUMEDOWN, AKEYCODE_VOLUME_DOWN },
+    { KEY_VOLUMEUP, AKEYCODE_VOLUME_UP },
+    { KEY_MUTE, AKEYCODE_VOLUME_MUTE },
+    { KEY_MUTE, AKEYCODE_MUTE },
+
+    { KEY_POWER, AKEYCODE_POWER },
+    { KEY_HOMEPAGE, AKEYCODE_HOME },
+    { KEY_BACK, AKEYCODE_BACK },
+
+    // Media Control
+    { KEY_PLAYPAUSE, AKEYCODE_MEDIA_PLAY_PAUSE },
+    { KEY_PLAY, AKEYCODE_MEDIA_PLAY },
+    { KEY_PAUSECD, AKEYCODE_MEDIA_PAUSE },
+    { KEY_NEXTSONG, AKEYCODE_MEDIA_NEXT },
+    { KEY_PREVIOUSSONG, AKEYCODE_MEDIA_PREVIOUS },
+    { KEY_STOPCD, AKEYCODE_MEDIA_STOP },
+    { KEY_RECORD, AKEYCODE_MEDIA_RECORD },
+    { KEY_REWIND, AKEYCODE_MEDIA_REWIND },
+    { KEY_FASTFORWARD, AKEYCODE_MEDIA_FAST_FORWARD },
+
+    // TV Control
+    { KEY_0, AKEYCODE_0 },
+    { KEY_1, AKEYCODE_1 },
+    { KEY_2, AKEYCODE_2 },
+    { KEY_3, AKEYCODE_3 },
+    { KEY_4, AKEYCODE_4 },
+    { KEY_5, AKEYCODE_5 },
+    { KEY_6, AKEYCODE_6 },
+    { KEY_7, AKEYCODE_7 },
+    { KEY_8, AKEYCODE_8 },
+    { KEY_9, AKEYCODE_9 },
+    { KEY_BACKSPACE, AKEYCODE_DEL },
+    { KEY_ENTER, AKEYCODE_ENTER},
+    { KEY_CHANNELUP, AKEYCODE_CHANNEL_UP },
+    { KEY_CHANNELDOWN, AKEYCODE_CHANNEL_DOWN },
+
+    // Old School TV Controls
+    { KEY_F1, AKEYCODE_F1 },
+    { KEY_F2, AKEYCODE_F2 },
+    { KEY_F3, AKEYCODE_F3 },
+    { KEY_F4, AKEYCODE_F4 },
+    { KEY_F5, AKEYCODE_F5 },
+    { KEY_F6, AKEYCODE_F6 },
+    { KEY_F7, AKEYCODE_F7 },
+    { KEY_F8, AKEYCODE_F8 },
+    { KEY_F9, AKEYCODE_F9 },
+    { KEY_F10, AKEYCODE_F10 },
+    { KEY_F11, AKEYCODE_F11 },
+    { KEY_F12, AKEYCODE_F12 },
+    { KEY_FN_F1, AKEYCODE_F1 },
+    { KEY_FN_F2, AKEYCODE_F2 },
+    { KEY_FN_F3, AKEYCODE_F3 },
+    { KEY_FN_F4, AKEYCODE_F4 },
+    { KEY_FN_F5, AKEYCODE_F5 },
+    { KEY_FN_F6, AKEYCODE_F6 },
+    { KEY_FN_F7, AKEYCODE_F7 },
+    { KEY_FN_F8, AKEYCODE_F8 },
+    { KEY_FN_F9, AKEYCODE_F9 },
+    { KEY_FN_F10, AKEYCODE_F10 },
+    { KEY_FN_F11, AKEYCODE_F11 },
+    { KEY_FN_F12, AKEYCODE_F12 },
+    { KEY_TV, AKEYCODE_TV },
+    { KEY_RED, AKEYCODE_PROG_RED },
+    { KEY_GREEN, AKEYCODE_PROG_GREEN },
+    { KEY_YELLOW, AKEYCODE_PROG_YELLOW },
+    { KEY_BLUE, AKEYCODE_PROG_BLUE },
+
+    { KEY_FAVORITES, AKEYCODE_BUTTON_MODE},
+    { KEY_WWW, AKEYCODE_EXPLORER },
+    { KEY_MENU, AKEYCODE_MENU },
+    { KEY_INFO, AKEYCODE_INFO },
+    { KEY_EPG, AKEYCODE_GUIDE },
+    { KEY_TEXT, AKEYCODE_TV_TELETEXT },
+    { KEY_SUBTITLE, AKEYCODE_CAPTIONS },
+    { KEY_PVR, AKEYCODE_DVR},
+    { KEY_AUDIO, AKEYCODE_MEDIA_AUDIO_TRACK},
+    { KEY_OPTION, AKEYCODE_SETTINGS},
+
+    // Gamepad buttons
+    { KEY_UP, AKEYCODE_DPAD_UP },
+    { KEY_DOWN, AKEYCODE_DPAD_DOWN },
+    { KEY_LEFT, AKEYCODE_DPAD_LEFT },
+    { KEY_RIGHT, AKEYCODE_DPAD_RIGHT },
+    { KEY_SELECT, AKEYCODE_DPAD_CENTER },
+    { BTN_A, AKEYCODE_BUTTON_A },
+    { BTN_B, AKEYCODE_BUTTON_B },
+    { BTN_X, AKEYCODE_BUTTON_X },
+    { BTN_Y, AKEYCODE_BUTTON_Y },
+
+    { KEY_SEARCH, AKEYCODE_SEARCH },
+};
+
+} // namespace android
+
+#endif // SERVICE_JNI_KEYS_H_
diff --git a/services/core/jni/com_android_server_tv_TvUinputBridge.cpp b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
new file mode 100644
index 0000000..de115c8
--- /dev/null
+++ b/services/core/jni/com_android_server_tv_TvUinputBridge.cpp
@@ -0,0 +1,308 @@
+/*
+ * Copyright 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.
+ */
+
+#define LOG_TAG "TvRemote-native-uiBridge"
+
+#include "com_android_server_tv_TvKeys.h"
+
+#include "jni.h"
+#include <android_runtime/AndroidRuntime.h>
+#include <ScopedUtfChars.h>
+#include <android/keycodes.h>
+
+#include <utils/BitSet.h>
+#include <utils/Errors.h>
+#include <utils/misc.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#include <ctype.h>
+#include <linux/input.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <time.h>
+#include <stdint.h>
+#include <map>
+#include <fcntl.h>
+#include <linux/uinput.h>
+#include <signal.h>
+#include <sys/inotify.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+// Refer to EventHub.h
+#define MSC_ANDROID_TIME_SEC 0x6
+#define MSC_ANDROID_TIME_USEC 0x7
+
+#define SLOT_UNKNOWN -1
+
+namespace android {
+
+static std::map<int32_t,int> keysMap;
+static std::map<int32_t,int32_t> slotsMap;
+static BitSet32 mtSlots;
+
+static void initKeysMap() {
+    if (keysMap.empty()) {
+        for (size_t i = 0; i < NELEM(KEYS); i++) {
+            keysMap[KEYS[i].androidKeyCode] = KEYS[i].linuxKeyCode;
+        }
+    }
+}
+
+static int32_t getLinuxKeyCode(int32_t androidKeyCode) {
+    std::map<int,int>::iterator it = keysMap.find(androidKeyCode);
+    if (it != keysMap.end()) {
+        return it->second;
+    }
+    return KEY_UNKNOWN;
+}
+
+static int findSlot(int32_t pointerId) {
+    std::map<int,int>::iterator it = slotsMap.find(pointerId);
+    if (it != slotsMap.end()) {
+        return it->second;
+    }
+    return SLOT_UNKNOWN;
+}
+
+static int assignSlot(int32_t pointerId) {
+    if (!mtSlots.isFull()) {
+        uint32_t slot = mtSlots.markFirstUnmarkedBit();
+        slotsMap[pointerId] = slot;
+        return slot;
+    }
+    return SLOT_UNKNOWN;
+}
+
+static void unassignSlot(int32_t pointerId) {
+    int slot = findSlot(pointerId);
+    if (slot != SLOT_UNKNOWN) {
+        mtSlots.clearBit(slot);
+        slotsMap.erase(pointerId);
+    }
+}
+
+class NativeConnection {
+public:
+    ~NativeConnection();
+
+    static NativeConnection* open(const char* name, const char* uniqueId,
+            int32_t width, int32_t height, int32_t maxPointerId);
+
+    void sendEvent(int32_t type, int32_t code, int32_t value);
+
+    int32_t getMaxPointers() const { return mMaxPointers; }
+
+private:
+    NativeConnection(int fd, int32_t maxPointers);
+
+    const int mFd;
+    const int32_t mMaxPointers;
+};
+
+NativeConnection::NativeConnection(int fd, int32_t maxPointers) :
+        mFd(fd), mMaxPointers(maxPointers) {
+}
+
+NativeConnection::~NativeConnection() {
+    ALOGI("Un-Registering uinput device %d.", mFd);
+    ioctl(mFd, UI_DEV_DESTROY);
+    close(mFd);
+}
+
+NativeConnection* NativeConnection::open(const char* name, const char* uniqueId,
+        int32_t width, int32_t height, int32_t maxPointers) {
+    ALOGI("Registering uinput device %s: touch pad size %dx%d, "
+            "max pointers %d.", name, width, height, maxPointers);
+
+    int fd = ::open("/dev/uinput", O_WRONLY | O_NDELAY);
+    if (fd < 0) {
+        ALOGE("Cannot open /dev/uinput: %s.", strerror(errno));
+        return nullptr;
+    }
+
+    struct uinput_user_dev uinp;
+    memset(&uinp, 0, sizeof(struct uinput_user_dev));
+    strlcpy(uinp.name, name, UINPUT_MAX_NAME_SIZE);
+    uinp.id.version = 1;
+    uinp.id.bustype = BUS_VIRTUAL;
+
+    // initialize keymap
+    initKeysMap();
+
+    // write device unique id to the phys property
+    ioctl(fd, UI_SET_PHYS, uniqueId);
+
+    // set the keys mapped
+    ioctl(fd, UI_SET_EVBIT, EV_KEY);
+    for (size_t i = 0; i < NELEM(KEYS); i++) {
+        ioctl(fd, UI_SET_KEYBIT, KEYS[i].linuxKeyCode);
+    }
+
+    // set the misc events maps
+    ioctl(fd, UI_SET_EVBIT, EV_MSC);
+    ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_SEC);
+    ioctl(fd, UI_SET_MSCBIT, MSC_ANDROID_TIME_USEC);
+
+    // register the input device
+    if (write(fd, &uinp, sizeof(uinp)) != sizeof(uinp)) {
+        ALOGE("Cannot write uinput_user_dev to fd %d: %s.", fd, strerror(errno));
+        close(fd);
+        return NULL;
+    }
+    if (ioctl(fd, UI_DEV_CREATE) != 0) {
+        ALOGE("Unable to create uinput device: %s.", strerror(errno));
+        close(fd);
+        return nullptr;
+    }
+
+    ALOGV("Created uinput device, fd=%d.", fd);
+    return new NativeConnection(fd, maxPointers);
+}
+
+void NativeConnection::sendEvent(int32_t type, int32_t code, int32_t value) {
+    struct input_event iev;
+    memset(&iev, 0, sizeof(iev));
+    iev.type = type;
+    iev.code = code;
+    iev.value = value;
+    write(mFd, &iev, sizeof(iev));
+}
+
+
+static jlong nativeOpen(JNIEnv* env, jclass clazz,
+        jstring nameStr, jstring uniqueIdStr,
+        jint width, jint height, jint maxPointers) {
+    ScopedUtfChars name(env, nameStr);
+    ScopedUtfChars uniqueId(env, uniqueIdStr);
+
+    NativeConnection* connection = NativeConnection::open(name.c_str(), uniqueId.c_str(),
+            width, height, maxPointers);
+    return reinterpret_cast<jlong>(connection);
+}
+
+static void nativeClose(JNIEnv* env, jclass clazz, jlong ptr) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+    delete connection;
+}
+
+static void nativeSendTimestamp(JNIEnv* env, jclass clazz, jlong ptr, jlong timestamp) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_SEC, timestamp / 1000L);
+    connection->sendEvent(EV_MSC, MSC_ANDROID_TIME_USEC, (timestamp % 1000L) * 1000L);
+}
+
+static void nativeSendKey(JNIEnv* env, jclass clazz, jlong ptr, jint keyCode, jboolean down) {
+    int32_t code = getLinuxKeyCode(keyCode);
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+    if (code != KEY_UNKNOWN) {
+        connection->sendEvent(EV_KEY, code, down ? 1 : 0);
+    } else {
+        ALOGE("Received an unknown keycode of %d.", keyCode);
+    }
+}
+
+static void nativeSendPointerDown(JNIEnv* env, jclass clazz, jlong ptr,
+        jint pointerId, jint x, jint y) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    int32_t slot = findSlot(pointerId);
+    if (slot == SLOT_UNKNOWN) {
+        slot = assignSlot(pointerId);
+    }
+    if (slot != SLOT_UNKNOWN) {
+        connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
+        connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, pointerId);
+        connection->sendEvent(EV_ABS, ABS_MT_POSITION_X, x);
+        connection->sendEvent(EV_ABS, ABS_MT_POSITION_Y, y);
+    }
+}
+
+static void nativeSendPointerUp(JNIEnv* env, jclass clazz, jlong ptr,
+        jint pointerId) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    int32_t slot = findSlot(pointerId);
+    if (slot != SLOT_UNKNOWN) {
+        connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
+        connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+        unassignSlot(pointerId);
+    }
+}
+
+static void nativeSendPointerSync(JNIEnv* env, jclass clazz, jlong ptr) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+    connection->sendEvent(EV_SYN, SYN_REPORT, 0);
+}
+
+static void nativeClear(JNIEnv* env, jclass clazz, jlong ptr) {
+    NativeConnection* connection = reinterpret_cast<NativeConnection*>(ptr);
+
+    // Clear keys.
+    for (size_t i = 0; i < NELEM(KEYS); i++) {
+        connection->sendEvent(EV_KEY, KEYS[i].linuxKeyCode, 0);
+    }
+
+    // Clear pointers.
+    int32_t slot = SLOT_UNKNOWN;
+    for (int32_t i = 0; i < connection->getMaxPointers(); i++) {
+        slot = findSlot(i);
+        if (slot != SLOT_UNKNOWN) {
+            connection->sendEvent(EV_ABS, ABS_MT_SLOT, slot);
+            connection->sendEvent(EV_ABS, ABS_MT_TRACKING_ID, -1);
+        }
+    }
+
+    // Sync pointer events
+    connection->sendEvent(EV_SYN, SYN_REPORT, 0);
+}
+
+/*
+ * JNI registration
+ */
+
+static JNINativeMethod gUinputBridgeMethods[] = {
+    { "nativeOpen", "(Ljava/lang/String;Ljava/lang/String;III)J",
+        (void*)nativeOpen },
+    { "nativeClose", "(J)V",
+        (void*)nativeClose },
+    { "nativeSendTimestamp", "(JJ)V",
+        (void*)nativeSendTimestamp },
+    { "nativeSendKey", "(JIZ)V",
+        (void*)nativeSendKey },
+    { "nativeSendPointerDown", "(JIII)V",
+        (void*)nativeSendPointerDown },
+    { "nativeSendPointerUp", "(JI)V",
+        (void*)nativeSendPointerUp },
+    { "nativeClear", "(J)V",
+        (void*)nativeClear },
+    { "nativeSendPointerSync", "(J)V",
+        (void*)nativeSendPointerSync },
+};
+
+int register_android_server_tv_TvUinputBridge(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "com/android/server/tv/UinputBridge",
+              gUinputBridgeMethods, NELEM(gUinputBridgeMethods));
+
+    LOG_FATAL_IF(res < 0, "Unable to register native methods.");
+    (void)res; // Don't complain about unused variable in the LOG_NDEBUG case
+
+    return 0;
+}
+
+} // namespace android
diff --git a/services/core/jni/onload.cpp b/services/core/jni/onload.cpp
index be99673..d3341e5 100644
--- a/services/core/jni/onload.cpp
+++ b/services/core/jni/onload.cpp
@@ -41,6 +41,7 @@
 int register_android_server_location_FlpHardwareProvider(JNIEnv* env);
 int register_android_server_connectivity_Vpn(JNIEnv* env);
 int register_android_server_hdmi_HdmiCecController(JNIEnv* env);
+int register_android_server_tv_TvUinputBridge(JNIEnv* env);
 int register_android_server_tv_TvInputHal(JNIEnv* env);
 int register_android_server_PersistentDataBlockService(JNIEnv* env);
 int register_android_server_Watchdog(JNIEnv* env);
@@ -81,6 +82,7 @@
     register_android_server_ConsumerIrService(env);
     register_android_server_BatteryStatsService(env);
     register_android_server_hdmi_HdmiCecController(env);
+    register_android_server_tv_TvUinputBridge(env);
     register_android_server_tv_TvInputHal(env);
     register_android_server_PersistentDataBlockService(env);
     register_android_server_Watchdog(env);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 45a7311..56e2001 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -4218,6 +4218,23 @@
         }
     }
 
+    private void removeCaApprovalsIfNeeded(int userId) {
+        for (UserInfo userInfo : mUserManager.getProfiles(userId)) {
+            boolean isSecure = mLockPatternUtils.isSecure(userInfo.id);
+            if (userInfo.isManagedProfile()){
+                isSecure |= mLockPatternUtils.isSecure(getProfileParentId(userInfo.id));
+            }
+            if (!isSecure) {
+                synchronized (this) {
+                    getUserData(userInfo.id).mAcceptedCaCertificates.clear();
+                    saveSettingsLocked(userInfo.id);
+                }
+
+                new MonitoringCertNotificationTask().execute(userInfo.id);
+            }
+        }
+    }
+
     @Override
     public boolean installCaCert(ComponentName admin, byte[] certBuffer) throws RemoteException {
         enforceCanManageCaCerts(admin);
@@ -4644,6 +4661,7 @@
                         DeviceAdminReceiver.ACTION_PASSWORD_CHANGED,
                         DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD, userHandle);
             }
+            removeCaApprovalsIfNeeded(userHandle);
         } finally {
             mInjector.binderRestoreCallingIdentity(ident);
         }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8c2f559..00b83841 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -90,6 +90,7 @@
 import com.android.server.storage.DeviceStorageMonitorService;
 import com.android.server.telecom.TelecomLoaderService;
 import com.android.server.trust.TrustManagerService;
+import com.android.server.tv.TvRemoteService;
 import com.android.server.tv.TvInputManagerService;
 import com.android.server.twilight.TwilightService;
 import com.android.server.usage.UsageStatsService;
@@ -165,6 +166,10 @@
     private static final String UNCRYPT_PACKAGE_FILE = "/cache/recovery/uncrypt_file";
     private static final String BLOCK_MAP_FILE = "/cache/recovery/block.map";
 
+    // maximum number of binder threads used for system_server
+    // will be higher than the system default
+    private static final int sMaxBinderThreads = 31;
+
     /**
      * Default theme used by the system context. This is used to style
      * system-provided dialogs, such as the Power Off dialog, and other
@@ -285,6 +290,9 @@
             // Ensure binder calls into the system always run at foreground priority.
             BinderInternal.disableBackgroundScheduling(true);
 
+            // Increase the number of binder threads in system_server
+            BinderInternal.setMaxThreads(sMaxBinderThreads);
+
             // Prepare the main looper thread (this thread).
             android.os.Process.setThreadPriority(
                 android.os.Process.THREAD_PRIORITY_FOREGROUND);
@@ -1104,6 +1112,10 @@
                 mSystemServiceManager.startService(MediaResourceMonitorService.class);
             }
 
+            if (mPackageManager.hasSystemFeature(PackageManager.FEATURE_LEANBACK)) {
+                mSystemServiceManager.startService(TvRemoteService.class);
+            }
+
             if (!disableNonCoreServices) {
                 traceBeginAndSlog("StartMediaRouterService");
                 try {
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 52701d5..6d0808f 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -264,8 +264,8 @@
             mInterfaceBroadcastAddr = new PacketSocketAddress(mIface.getIndex(),
                     DhcpPacket.ETHER_BROADCAST);
             return true;
-        } catch(SocketException e) {
-            Log.wtf(TAG, "Can't determine ifindex or MAC address for " + mIfaceName);
+        } catch(SocketException | NullPointerException e) {
+            Log.e(TAG, "Can't determine ifindex or MAC address for " + mIfaceName, e);
             return false;
         }
     }
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index 59ebf1b..5667e34 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -690,7 +690,7 @@
             final InterfaceConfiguration ifcg = new InterfaceConfiguration();
             ifcg.setLinkAddress(new LinkAddress("0.0.0.0/0"));
             mNwService.setInterfaceConfig(mInterfaceName, ifcg);
-        } catch (RemoteException e) {
+        } catch (IllegalStateException | RemoteException e) {
             Log.e(mTag, "ALERT: Failed to clear IPv4 address on interface " + mInterfaceName, e);
         }
     }
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index c8dbe02..27600a7 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -24,9 +24,7 @@
 import android.net.LinkProperties.ProvisioningChange;
 import android.net.ProxyInfo;
 import android.net.RouteInfo;
-import android.net.metrics.IpReachabilityMonitorMessageEvent;
-import android.net.metrics.IpReachabilityMonitorProbeEvent;
-import android.net.metrics.IpReachabilityMonitorLostEvent;
+import android.net.metrics.IpReachabilityEvent;
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
@@ -168,47 +166,54 @@
      * Make the kernel perform neighbor reachability detection (IPv4 ARP or IPv6 ND)
      * for the given IP address on the specified interface index.
      *
-     * @return true, if the request was successfully passed to the kernel; false otherwise.
+     * @return 0 if the request was successfully passed to the kernel; otherwise return
+     *         a non-zero error code.
      */
-    public static boolean probeNeighbor(int ifIndex, InetAddress ip) {
-        final long IO_TIMEOUT = 300L;
+    private static int probeNeighbor(int ifIndex, InetAddress ip) {
         final String msgSnippet = "probing ip=" + ip.getHostAddress() + "%" + ifIndex;
         if (DBG) { Log.d(TAG, msgSnippet); }
 
         final byte[] msg = RtNetlinkNeighborMessage.newNewNeighborMessage(
                 1, ip, StructNdMsg.NUD_PROBE, ifIndex, null);
-        boolean returnValue = false;
 
+        int errno = -OsConstants.EPROTO;
         try (NetlinkSocket nlSocket = new NetlinkSocket(OsConstants.NETLINK_ROUTE)) {
+            final long IO_TIMEOUT = 300L;
             nlSocket.connectToKernel();
             nlSocket.sendMessage(msg, 0, msg.length, IO_TIMEOUT);
             final ByteBuffer bytes = nlSocket.recvMessage(IO_TIMEOUT);
+            // recvMessage() guaranteed to not return null if it did not throw.
             final NetlinkMessage response = NetlinkMessage.parse(bytes);
             if (response != null && response instanceof NetlinkErrorMessage &&
-                    (((NetlinkErrorMessage) response).getNlMsgError() != null) &&
-                    (((NetlinkErrorMessage) response).getNlMsgError().error == 0)) {
-                returnValue = true;
-            } else {
-                String errmsg;
-                if (bytes == null) {
-                    errmsg = "null recvMessage";
-                } else if (response == null) {
-                    bytes.position(0);
-                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
-                } else {
+                    (((NetlinkErrorMessage) response).getNlMsgError() != null)) {
+                errno = ((NetlinkErrorMessage) response).getNlMsgError().error;
+                if (errno != 0) {
                     // TODO: consider ignoring EINVAL (-22), which appears to be
                     // normal when probing a neighbor for which the kernel does
                     // not already have / no longer has a link layer address.
+                    Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + response.toString());
+                }
+            } else {
+                String errmsg;
+                if (response == null) {
+                    bytes.position(0);
+                    errmsg = "raw bytes: " + NetlinkConstants.hexify(bytes);
+                } else {
                     errmsg = response.toString();
                 }
                 Log.e(TAG, "Error " + msgSnippet + ", errmsg=" + errmsg);
             }
-        } catch (ErrnoException | InterruptedIOException | SocketException e) {
-            Log.d(TAG, "Error " + msgSnippet, e);
+        } catch (ErrnoException e) {
+            Log.e(TAG, "Error " + msgSnippet, e);
+            errno = -e.errno;
+        } catch (InterruptedIOException e) {
+            Log.e(TAG, "Error " + msgSnippet, e);
+            errno = -OsConstants.ETIMEDOUT;
+        } catch (SocketException e) {
+            Log.e(TAG, "Error " + msgSnippet, e);
+            errno = -OsConstants.EIO;
         }
-        IpReachabilityMonitorProbeEvent.logEvent("ifindex-" + ifIndex, ip.getHostAddress(),
-                returnValue);
-        return returnValue;
+        return errno;
     }
 
     public IpReachabilityMonitor(Context context, String ifName, Callback callback)
@@ -354,7 +359,7 @@
         }
 
         if (delta == ProvisioningChange.LOST_PROVISIONING) {
-            IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
+            IpReachabilityEvent.logProvisioningLost(mInterfaceName);
             final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
             Log.w(TAG, logMsg);
             if (mCallback != null) {
@@ -362,6 +367,8 @@
                 // an InetAddress argument.
                 mCallback.notifyLost(ip, logMsg);
             }
+        } else {
+            IpReachabilityEvent.logNudFailed(mInterfaceName);
         }
     }
 
@@ -385,7 +392,8 @@
             if (!stillRunning()) {
                 break;
             }
-            probeNeighbor(mInterfaceIndex, target);
+            final int returnValue = probeNeighbor(mInterfaceIndex, target);
+            IpReachabilityEvent.logProbeEvent(mInterfaceName, returnValue);
         }
     }
 
@@ -523,8 +531,6 @@
 
             final short msgType = neighMsg.getHeader().nlmsg_type;
             final short nudState = ndMsg.ndm_state;
-            IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
-                    destination.getHostAddress(), msgType, nudState);
             final String eventMsg = "NeighborEvent{"
                     + "elapsedMs=" + whenMs + ", "
                     + destination.getHostAddress() + ", "
diff --git a/services/net/java/android/net/util/Stopwatch.java b/services/net/java/android/net/util/Stopwatch.java
new file mode 100644
index 0000000..cb15ee5
--- /dev/null
+++ b/services/net/java/android/net/util/Stopwatch.java
@@ -0,0 +1,75 @@
+/*
+ * 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.net.util;
+
+import android.os.SystemClock;
+
+
+/**
+ * @hide
+ */
+public class Stopwatch {
+    private long mStartTimeMs;
+    private long mStopTimeMs;
+
+    public boolean isStarted() {
+        return (mStartTimeMs > 0);
+    }
+
+    public boolean isStopped() {
+        return (mStopTimeMs > 0);
+    }
+
+    public boolean isRunning() {
+        return (isStarted() && !isStopped());
+    }
+
+    // Returning |this| makes possible the following usage pattern:
+    //
+    //     Stopwatch s = new Stopwatch().start();
+    public Stopwatch start() {
+        if (!isStarted()) {
+            mStartTimeMs = SystemClock.elapsedRealtime();
+        }
+        return this;
+    }
+
+    // Returns the total time recorded, in milliseconds, or 0 if not started.
+    public long stop() {
+        if (isRunning()) {
+            mStopTimeMs = SystemClock.elapsedRealtime();
+        }
+        // Return either the delta after having stopped, or 0.
+        return (mStopTimeMs - mStartTimeMs);
+    }
+
+    // Returns the total time recorded to date, in milliseconds.
+    // If the Stopwatch is not running, returns the same value as stop(),
+    // i.e. either the total time recorded before stopping or 0.
+    public long lap() {
+        if (isRunning()) {
+            return (SystemClock.elapsedRealtime() - mStartTimeMs);
+        } else {
+            return stop();
+        }
+    }
+
+    public void reset() {
+        mStartTimeMs = 0;
+        mStopTimeMs = 0;
+    }
+}
diff --git a/services/print/java/com/android/server/print/UserState.java b/services/print/java/com/android/server/print/UserState.java
index 026942e..7182161 100644
--- a/services/print/java/com/android/server/print/UserState.java
+++ b/services/print/java/com/android/server/print/UserState.java
@@ -593,7 +593,11 @@
                     new ListenerRecord<IPrintServicesChangeListener>(listener) {
                         @Override
                         public void onBinderDied() {
-                            mPrintServicesChangeListenerRecords.remove(this);
+                            synchronized (mLock) {
+                                if (mPrintServicesChangeListenerRecords != null) {
+                                    mPrintServicesChangeListenerRecords.remove(this);
+                                }
+                            }
                         }
                     });
         }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 23f186c..7017d81 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -42,6 +42,7 @@
     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
     <uses-permission android:name="android.permission.PACKET_KEEPALIVE_OFFLOAD" />
+    <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
 
     <application>
         <uses-library android:name="android.test.runner" />
diff --git a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
index 26eed24..4fae4a7 100644
--- a/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/ConnectivityServiceTest.java
@@ -74,6 +74,7 @@
 import com.android.server.net.NetworkPinner;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.LinkedBlockingQueue;
 import java.util.concurrent.TimeUnit;
@@ -1788,4 +1789,96 @@
         waitFor(cv);
         assertPinnedToWifiWithCellDefault();
     }
+
+    @SmallTest
+    public void testNetworkRequestMaximum() {
+        final int MAX_REQUESTS = 100;
+        // Test that the limit is enforced when MAX_REQUESTS simultaneous requests are added.
+        NetworkRequest networkRequest = new NetworkRequest.Builder().build();
+        ArrayList<NetworkCallback> networkCallbacks = new ArrayList<NetworkCallback>();
+        try {
+            for (int i = 0; i < MAX_REQUESTS; i++) {
+                NetworkCallback networkCallback = new NetworkCallback();
+                mCm.requestNetwork(networkRequest, networkCallback);
+                networkCallbacks.add(networkCallback);
+            }
+            fail("Registering " + MAX_REQUESTS + " NetworkRequests did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (NetworkCallback networkCallback : networkCallbacks) {
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        networkCallbacks.clear();
+
+        try {
+            for (int i = 0; i < MAX_REQUESTS; i++) {
+                NetworkCallback networkCallback = new NetworkCallback();
+                mCm.registerNetworkCallback(networkRequest, networkCallback);
+                networkCallbacks.add(networkCallback);
+            }
+            fail("Registering " + MAX_REQUESTS + " NetworkCallbacks did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (NetworkCallback networkCallback : networkCallbacks) {
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        networkCallbacks.clear();
+
+        ArrayList<PendingIntent> pendingIntents = new ArrayList<PendingIntent>();
+        try {
+            for (int i = 0; i < MAX_REQUESTS + 1; i++) {
+                PendingIntent pendingIntent =
+                        PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
+                mCm.requestNetwork(networkRequest, pendingIntent);
+                pendingIntents.add(pendingIntent);
+            }
+            fail("Registering " + MAX_REQUESTS +
+                    " PendingIntent NetworkRequests did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (PendingIntent pendingIntent : pendingIntents) {
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+        pendingIntents.clear();
+
+        try {
+            for (int i = 0; i < MAX_REQUESTS + 1; i++) {
+                PendingIntent pendingIntent =
+                        PendingIntent.getBroadcast(mContext, 0, new Intent("a" + i), 0);
+                mCm.registerNetworkCallback(networkRequest, pendingIntent);
+                pendingIntents.add(pendingIntent);
+            }
+            fail("Registering " + MAX_REQUESTS +
+                    " PendingIntent NetworkCallbacks did not throw exception");
+        } catch (IllegalArgumentException expected) {}
+        for (PendingIntent pendingIntent : pendingIntents) {
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+        pendingIntents.clear();
+        mService.waitForIdle(5000);
+
+        // Test that the limit is not hit when MAX_REQUESTS requests are added and removed.
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            NetworkCallback networkCallback = new NetworkCallback();
+            mCm.requestNetwork(networkRequest, networkCallback);
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        mService.waitForIdle();
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            NetworkCallback networkCallback = new NetworkCallback();
+            mCm.registerNetworkCallback(networkRequest, networkCallback);
+            mCm.unregisterNetworkCallback(networkCallback);
+        }
+        mService.waitForIdle();
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            PendingIntent pendingIntent =
+                    PendingIntent.getBroadcast(mContext, 0, new Intent("b" + i), 0);
+            mCm.requestNetwork(networkRequest, pendingIntent);
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+        mService.waitForIdle();
+        for (int i = 0; i < MAX_REQUESTS; i++) {
+            PendingIntent pendingIntent =
+                    PendingIntent.getBroadcast(mContext, 0, new Intent("c" + i), 0);
+            mCm.registerNetworkCallback(networkRequest, pendingIntent);
+            mCm.unregisterNetworkCallback(pendingIntent);
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
index 4468857..ef9739d 100644
--- a/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/accounts/AccountManagerServiceTest.java
@@ -32,6 +32,7 @@
 import android.content.pm.RegisteredServicesCache.ServiceInfo;
 import android.content.pm.RegisteredServicesCacheListener;
 import android.content.pm.UserInfo;
+import android.database.Cursor;
 import android.database.DatabaseErrorHandler;
 import android.database.sqlite.SQLiteDatabase;
 import android.os.Bundle;
@@ -64,15 +65,14 @@
         Context realTestContext = getContext();
         Context mockContext = new MyMockContext(realTestContext);
         setContext(mockContext);
-        mAms = new MyAccountManagerService(getContext(),
-                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realTestContext);
+        mAms = createAccountManagerService(mockContext, realTestContext);
     }
 
     @Override
     protected void tearDown() throws Exception {
-        new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)).delete();
-        new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)).delete();
-        new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)).delete();
+        SQLiteDatabase.deleteDatabase(new File(mAms.getCeDatabaseName(UserHandle.USER_SYSTEM)));
+        SQLiteDatabase.deleteDatabase(new File(mAms.getDeDatabaseName(UserHandle.USER_SYSTEM)));
+        SQLiteDatabase.deleteDatabase(new File(mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM)));
         super.tearDown();
     }
 
@@ -88,7 +88,7 @@
     }
 
     public void testCheckAddAccount() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Account a21 = new Account("account2", "type1");
         Account a31 = new Account("account3", "type1");
@@ -129,7 +129,7 @@
     }
 
     public void testPasswords() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Account a12 = new Account("account1", "type2");
         mAms.addAccountExplicitly(a11, "p11", null);
@@ -145,7 +145,7 @@
     }
 
     public void testUserdata() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Bundle u11 = new Bundle();
         u11.putString("a", "a_a11");
@@ -178,7 +178,7 @@
     }
 
     public void testAuthtokens() throws Exception {
-        unlockUser(UserHandle.USER_SYSTEM);
+        unlockSystemUser();
         Account a11 = new Account("account1", "type1");
         Account a12 = new Account("account1", "type2");
         mAms.addAccountExplicitly(a11, "p11", null);
@@ -211,10 +211,89 @@
         assertNull(mAms.peekAuthToken(a12, "att2"));
     }
 
-    private void unlockUser(int userId) {
+    public void testRemovedAccountSync() throws Exception {
+        unlockSystemUser();
+        Account a1 = new Account("account1", "type1");
+        Account a2 = new Account("account2", "type2");
+        mAms.addAccountExplicitly(a1, "p1", null);
+        mAms.addAccountExplicitly(a2, "p2", null);
+
+        Context originalContext = ((MyMockContext)getContext()).mTestContext;
+        // create a separate instance of AMS. It initially assumes that user0 is locked
+        AccountManagerService ams2 = createAccountManagerService(getContext(), originalContext);
+
+        // Verify that account can be removed when user is locked
+        ams2.removeAccountInternal(a1);
+        Account[] accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+        assertEquals(1, accounts.length);
+        assertEquals("Only a2 should be returned", a2, accounts[0]);
+
+        // Verify that CE db file is unchanged and still has 2 accounts
+        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+        int accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
+        assertEquals("CE database should still have 2 accounts", 2, accountsNumber);
+
+        // Unlock the user and verify that db has been updated
+        ams2.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
+        accountsNumber = readNumberOfAccountsFromDbFile(originalContext, ceDatabaseName);
+        assertEquals("CE database should now have 1 account", 2, accountsNumber);
+        accounts = ams2.getAccounts(UserHandle.USER_SYSTEM, mContext.getOpPackageName());
+        assertEquals(1, accounts.length);
+        assertEquals("Only a2 should be returned", a2, accounts[0]);
+    }
+
+    public void testPreNDatabaseMigration() throws Exception {
+        String preNDatabaseName = mAms.getPreNDatabaseName(UserHandle.USER_SYSTEM);
+        Context originalContext = ((MyMockContext) getContext()).mTestContext;
+        PreNTestDatabaseHelper.createV4Database(originalContext, preNDatabaseName);
+        // Assert that database was created with 1 account
+        int n = readNumberOfAccountsFromDbFile(originalContext, preNDatabaseName);
+        assertEquals("pre-N database should have 1 account", 1, n);
+
+        // Start testing
+        unlockSystemUser();
+        Account[] accounts = mAms.getAccounts(null, mContext.getOpPackageName());
+        assertEquals("1 account should be migrated", 1, accounts.length);
+        assertEquals(PreNTestDatabaseHelper.ACCOUNT_NAME, accounts[0].name);
+        assertEquals(PreNTestDatabaseHelper.ACCOUNT_PASSWORD, mAms.getPassword(accounts[0]));
+        assertEquals("Authtoken should be migrated",
+                PreNTestDatabaseHelper.TOKEN_STRING,
+                mAms.peekAuthToken(accounts[0], PreNTestDatabaseHelper.TOKEN_TYPE));
+
+        assertFalse("pre-N database file should be removed but was found at " + preNDatabaseName,
+                new File(preNDatabaseName).exists());
+
+        // Verify that ce/de files are present
+        String deDatabaseName = mAms.getDeDatabaseName(UserHandle.USER_SYSTEM);
+        String ceDatabaseName = mAms.getCeDatabaseName(UserHandle.USER_SYSTEM);
+        assertTrue("DE database file should be created at " + deDatabaseName,
+                new File(deDatabaseName).exists());
+        assertTrue("CE database file should be created at " + ceDatabaseName,
+                new File(ceDatabaseName).exists());
+    }
+
+    private int readNumberOfAccountsFromDbFile(Context context, String dbName) {
+        SQLiteDatabase ceDb = context.openOrCreateDatabase(dbName, 0, null);
+        try (Cursor cursor = ceDb.rawQuery("SELECT count(*) FROM accounts", null)) {
+            assertTrue(cursor.moveToNext());
+            return cursor.getInt(0);
+        }
+    }
+
+    private AccountManagerService createAccountManagerService(Context mockContext,
+            Context realContext) {
+        return new MyAccountManagerService(mockContext,
+                new MyMockPackageManager(), new MockAccountAuthenticatorCache(), realContext);
+    }
+
+    private void unlockSystemUser() {
+        mAms.onUserUnlocked(newIntentForUser(UserHandle.USER_SYSTEM));
+    }
+
+    private static Intent newIntentForUser(int userId) {
         Intent intent = new Intent();
         intent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
-        mAms.onUserUnlocked(intent);
+        return intent;
     }
 
     static public class MockAccountAuthenticatorCache implements IAccountAuthenticatorCache {
@@ -264,11 +343,13 @@
         private Context mTestContext;
         private AppOpsManager mAppOpsManager;
         private UserManager mUserManager;
+        private PackageManager mPackageManager;
 
         public MyMockContext(Context testContext) {
             this.mTestContext = testContext;
             this.mAppOpsManager = mock(AppOpsManager.class);
             this.mUserManager = mock(UserManager.class);
+            this.mPackageManager = mock(PackageManager.class);
             final UserInfo ui = new UserInfo(UserHandle.USER_SYSTEM, "user0", 0);
             when(mUserManager.getUserInfo(eq(ui.id))).thenReturn(ui);
         }
@@ -279,6 +360,11 @@
         }
 
         @Override
+        public PackageManager getPackageManager() {
+            return mPackageManager;
+        }
+
+        @Override
         public Object getSystemService(String name) {
             if (Context.APP_OPS_SERVICE.equals(name)) {
                 return mAppOpsManager;
diff --git a/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
new file mode 100644
index 0000000..97adbe6
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accounts/PreNTestDatabaseHelper.java
@@ -0,0 +1,98 @@
+/*
+ * 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.server.accounts;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.database.sqlite.SQLiteOpenHelper;
+
+/**
+ * Helper class for emulating pre-N database
+ */
+class PreNTestDatabaseHelper extends SQLiteOpenHelper {
+
+    public static final String TOKEN_STRING = "token-string-123";
+    public static final String ACCOUNT_TYPE = "type1";
+    public static final String ACCOUNT_NAME = "account@" + ACCOUNT_TYPE;
+    public static final String ACCOUNT_PASSWORD = "Password";
+    public static final String TOKEN_TYPE = "SID";
+
+    public PreNTestDatabaseHelper(Context context, String name) {
+        super(context, name, null, 4);
+    }
+
+    @Override
+    public void onCreate(SQLiteDatabase db) {
+        db.execSQL("CREATE TABLE accounts ( "
+                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                + "name TEXT NOT NULL, "
+                + "type TEXT NOT NULL, "
+                + "password TEXT, "
+                + "UNIQUE(name, type))");
+        db.execSQL("INSERT INTO accounts (name, type, password) VALUES "
+                + "('" + ACCOUNT_NAME + "', '" + ACCOUNT_TYPE + "', '" + ACCOUNT_PASSWORD + "')");
+
+        db.execSQL("CREATE TABLE authtokens (  "
+                + "_id INTEGER PRIMARY KEY AUTOINCREMENT,  "
+                + "accounts_id INTEGER NOT NULL, "
+                + "type TEXT NOT NULL,  "
+                + "authtoken TEXT, "
+                + "UNIQUE (accounts_id, type ))");
+        db.execSQL("INSERT INTO authtokens (accounts_id, type, authtoken) VALUES "
+                + "(1, '" + TOKEN_TYPE + "', '" + TOKEN_STRING + "')");
+
+        db.execSQL("CREATE TABLE grants (  "
+                + "accounts_id INTEGER NOT NULL, "
+                + "auth_token_type STRING NOT NULL,  "
+                + "uid INTEGER NOT NULL,  "
+                + "UNIQUE (accounts_id,auth_token_type,uid))");
+
+        db.execSQL("CREATE TABLE extras ( "
+                + "_id INTEGER PRIMARY KEY AUTOINCREMENT, "
+                + "accounts_id INTEGER, "
+                + "key TEXT NOT NULL, "
+                + "value TEXT, "
+                + "UNIQUE(accounts_id , key))");
+
+        db.execSQL("CREATE TABLE meta ( "
+                + "key TEXT PRIMARY KEY NOT NULL, "
+                + "value TEXT)");
+
+        db.execSQL(""
+                + " CREATE TRIGGER accountsDelete DELETE ON accounts "
+                + " BEGIN"
+                + "   DELETE FROM authtokens"
+                + "     WHERE accounts_id=OLD._id;"
+                + "   DELETE FROM extras"
+                + "     WHERE accounts_id=OLD._id;"
+                + "   DELETE FROM grants"
+                + "     WHERE accounts_id=OLD._id;"
+                + " END");
+    }
+
+    @Override
+    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
+        throw new UnsupportedOperationException("Upgrade of test database is not supported");
+    }
+
+    public static void createV4Database(Context context, String name) {
+        PreNTestDatabaseHelper helper = new PreNTestDatabaseHelper(context, name);
+        helper.getWritableDatabase();
+        helper.close();
+    }
+
+}
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1e9db18..3f9da4c 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -183,11 +183,11 @@
         try {
             if (mActiveSession == null || token != mActiveSession.mToken) {
                 Slog.w(TAG, "startVoiceActivity does not match active session");
-                return ActivityManager.START_CANCELED;
+                return ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
             }
             if (!mActiveSession.mShown) {
                 Slog.w(TAG, "startVoiceActivity not allowed on hidden session");
-                return ActivityManager.START_CANCELED;
+                return ActivityManager.START_VOICE_HIDDEN_SESSION;
             }
             intent = new Intent(intent);
             intent.addCategory(Intent.CATEGORY_VOICE);
diff --git a/telephony/java/android/telephony/ModemActivityInfo.java b/telephony/java/android/telephony/ModemActivityInfo.java
index 84883d8..03ce2d8 100644
--- a/telephony/java/android/telephony/ModemActivityInfo.java
+++ b/telephony/java/android/telephony/ModemActivityInfo.java
@@ -151,12 +151,24 @@
      * @return if the record is valid
      */
     public boolean isValid() {
-        int totalTxTimeMs = 0;
-        int txTime [] = getTxTimeMillis();
-        for (int i = 0; i < TX_POWER_LEVELS; i++) {
-            totalTxTimeMs += txTime[i];
+        for (int txVal : getTxTimeMillis()) {
+            if(txVal < 0) {
+                return false;
+            }
         }
-        return ((getIdleTimeMillis() >= 0) && (totalTxTimeMs >= 0)
-                && (getSleepTimeMillis() >= 0) && (getIdleTimeMillis() >= 0));
+
+        return ((getIdleTimeMillis() >= 0) && (getSleepTimeMillis() >= 0)
+                && (getRxTimeMillis() >= 0) && (getEnergyUsed() >= 0) && !isEmpty());
+    }
+
+    private boolean isEmpty() {
+        for (int txVal : getTxTimeMillis()) {
+            if(txVal != 0) {
+                return false;
+            }
+        }
+
+        return ((getIdleTimeMillis() == 0) && (getSleepTimeMillis() == 0)
+                && (getRxTimeMillis() == 0) && (getEnergyUsed() == 0));
     }
 }
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 69fdadf..343b110 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3605,14 +3605,21 @@
     }
 
     // ICC SIM Application Types
+    /** UICC application type is SIM */
     public static final int APPTYPE_SIM = PhoneConstants.APPTYPE_SIM;
+    /** UICC application type is USIM */
     public static final int APPTYPE_USIM = PhoneConstants.APPTYPE_USIM;
+    /** UICC application type is RUIM */
     public static final int APPTYPE_RUIM = PhoneConstants.APPTYPE_RUIM;
+    /** UICC application type is CSIM */
     public static final int APPTYPE_CSIM = PhoneConstants.APPTYPE_CSIM;
+    /** UICC application type is ISIM */
     public static final int APPTYPE_ISIM = PhoneConstants.APPTYPE_ISIM;
-    // authContext (parameter P2) when doing SIM challenge,
+    // authContext (parameter P2) when doing UICC challenge,
     // per 3GPP TS 31.102 (Section 7.1.2)
+    /** Authentication type for UICC challenge is EAP SIM. See RFC 4186 for details. */
     public static final int AUTHTYPE_EAP_SIM = PhoneConstants.AUTH_CONTEXT_EAP_SIM;
+    /** Authentication type for UICC challenge is EAP AKA. See RFC 4187 for details. */
     public static final int AUTHTYPE_EAP_AKA = PhoneConstants.AUTH_CONTEXT_EAP_AKA;
 
     /**
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2e5ed3f..330dbab 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -822,7 +822,13 @@
 
     /** @hide */
     @Override
-    public @Nullable String getServicesSystemSharedLibraryPackageName() {
+    public @NonNull String getServicesSystemSharedLibraryPackageName() {
+        throw new UnsupportedOperationException();
+    }
+
+    /** @hide */
+    @Override
+    public @NonNull String getSharedSystemSharedLibraryPackageName() {
         throw new UnsupportedOperationException();
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index 0a64b63..b3ed9e1 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -49,6 +49,7 @@
 import android.graphics.drawable.Drawable;
 import android.net.Uri;
 import android.os.Handler;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.os.storage.VolumeInfo;
 import java.util.List;
@@ -311,6 +312,11 @@
     }
 
     @Override
+    public @NonNull String getSharedSystemSharedLibraryPackageName() {
+        return null;
+    }
+
+    @Override
     public FeatureInfo[] getSystemAvailableFeatures() {
         return new FeatureInfo[0];
     }