Merge "Make AbsSavedState read using given ClassLoader" into nyc-dev
diff --git a/Android.mk b/Android.mk
index da53db7..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 \
@@ -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 b2e063a..15fc149 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -71,7 +71,6 @@
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
-    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -3424,6 +3423,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);
@@ -4926,6 +4926,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 +4947,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 +5199,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 +5241,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 +5258,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 +23023,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 +23061,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";
   }
@@ -36834,10 +36833,10 @@
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
-    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
+    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
-    field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
+    field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -43532,7 +43531,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);
@@ -43584,7 +43583,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();
@@ -43711,8 +43710,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 {
diff --git a/api/system-current.txt b/api/system-current.txt
index 374acfe..c489435 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";
@@ -103,11 +105,11 @@
     field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
     field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
-    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final java.lang.String GET_PROCESS_STATE_AND_OOM_SCORE = "android.permission.GET_PROCESS_STATE_AND_OOM_SCORE";
     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 +119,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 +227,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 +3547,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);
@@ -3821,6 +3828,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 +4135,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 +5069,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 +5090,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 +5343,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 +5385,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 +5402,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 +8901,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 +8949,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 +9056,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 +9067,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 +10092,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 +10244,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 +10547,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 +24747,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 +24802,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";
   }
@@ -30768,6 +30805,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;
@@ -31647,6 +31685,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();
@@ -32123,6 +32174,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 {
@@ -39717,10 +39781,10 @@
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
-    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
+    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
-    field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
+    field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -41032,6 +41096,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);
@@ -46479,7 +46544,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);
@@ -46531,7 +46596,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();
@@ -46659,8 +46724,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 {
diff --git a/api/test-current.txt b/api/test-current.txt
index 90f8e99..f6340b2 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -71,7 +71,6 @@
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
-    field public static final java.lang.String GET_PASSWORD_PRIVILEGED = "android.permission.GET_PASSWORD_PRIVILEGED";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
     field public static final java.lang.String INSTALL_LOCATION_PROVIDER = "android.permission.INSTALL_LOCATION_PROVIDER";
@@ -3424,6 +3423,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);
@@ -4926,6 +4926,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 +4947,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 +5199,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 +5241,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 +5258,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 +23091,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 +23129,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";
   }
@@ -36909,10 +36908,10 @@
     field public static final java.lang.String KEY_VOICEMAIL_NOTIFICATION_PERSISTENT_BOOL = "voicemail_notification_persistent_bool";
     field public static final java.lang.String KEY_VOICE_PRIVACY_DISABLE_UI_BOOL = "voice_privacy_disable_ui_bool";
     field public static final java.lang.String KEY_VOLTE_REPLACEMENT_RAT_INT = "volte_replacement_rat_int";
-    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
+    field public static final java.lang.String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required";
     field public static final java.lang.String KEY_VVM_DESTINATION_NUMBER_STRING = "vvm_destination_number_string";
     field public static final java.lang.String KEY_VVM_PORT_NUMBER_INT = "vvm_port_number_int";
-    field public static final java.lang.String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
+    field public static final java.lang.String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch";
     field public static final java.lang.String KEY_VVM_TYPE_STRING = "vvm_type_string";
     field public static final java.lang.String KEY_WORLD_PHONE_BOOL = "world_phone_bool";
   }
@@ -43609,7 +43608,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);
@@ -43661,7 +43660,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();
@@ -43788,8 +43787,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 {
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 5ea3903..0149952 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -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) {
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 2f7c550..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;
 
@@ -696,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;
+        }
     }
 
     /**
@@ -2360,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() {
@@ -2388,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) {
@@ -2410,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>() {
@@ -2445,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();
@@ -3087,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/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/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 39f8e19..dd05392 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -947,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}
@@ -3301,7 +3301,10 @@
             }
         }
 
-        private String loadHeaderAppName() {
+        /**
+         * @hide
+         */
+        public String loadHeaderAppName() {
             CharSequence name = null;
             final PackageManager pm = mContext.getPackageManager();
             if (mN.extras.containsKey(EXTRA_SUBSTITUTE_APP_NAME)) {
@@ -4326,7 +4329,7 @@
         CharSequence mUserDisplayName;
         CharSequence mConversationTitle;
         boolean mAllowGeneratedReplies = true;
-        ArrayList<Message> mMessages = new ArrayList<>();
+        List<Message> mMessages = new ArrayList<>();
 
         MessagingStyle() {
         }
@@ -4439,11 +4442,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));
             }
         }
 
@@ -4456,12 +4459,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);
             }
         }
 
@@ -4562,7 +4565,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;
@@ -4620,26 +4629,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
@@ -4677,49 +4666,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;
+                }
+            }
         }
     }
 
@@ -5461,6 +5465,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
@@ -6029,6 +6034,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/content/Intent.java b/core/java/android/content/Intent.java
index c8bf4d6..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";
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/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/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/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 81310c4..eb895ff 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) {
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 72d63ea..e3abb5d 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -612,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.
          *
@@ -631,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);
     }
 
@@ -832,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) {
@@ -849,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/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/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/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 250d9b7..e69ed35 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1210,6 +1210,16 @@
         }
     }
 
+    /**
+     * A counter meant to accept monotonically increasing values to its {@link #update(long, int)}
+     * method. The state of the timer according to its {@link TimeBase} will determine how much
+     * of the value is recorded.
+     *
+     * If the value being recorded resets, {@link #endSample()} can be called in order to
+     * account for the change. If the value passed in to {@link #update(long, int)} decreased
+     * between calls, the {@link #endSample()} is automatically called and the new value is
+     * expected to increase monotonically from that point on.
+     */
     public static class SamplingTimer extends Timer {
 
         /**
@@ -1262,16 +1272,21 @@
         }
 
         @VisibleForTesting
-        public SamplingTimer(Clocks clocks, TimeBase timeBase, boolean trackReportedValues) {
+        public SamplingTimer(Clocks clocks, TimeBase timeBase) {
             super(clocks, 0, timeBase);
-            mTrackingReportedValues = trackReportedValues;
+            mTrackingReportedValues = false;
             mTimeBaseRunning = timeBase.isRunning();
         }
 
-        public void setStale() {
-            mTrackingReportedValues = false;
-            mUnpluggedReportedTotalTime = 0;
-            mUnpluggedReportedCount = 0;
+        /**
+         * Ends the current sample, allowing subsequent values to {@link #update(long, int)} to
+         * be less than the values used for a previous invocation.
+         */
+        public void endSample() {
+            mTotalTime = computeRunTimeLocked(0 /* unused by us */);
+            mCount = computeCurrentCountLocked();
+            mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = 0;
+            mUnpluggedReportedCount = mCurrentReportedCount = 0;
         }
 
         public void setUpdateVersion(int version) {
@@ -1282,34 +1297,46 @@
             return mUpdateVersion;
         }
 
-        public void updateCurrentReportedCount(int count) {
-            if (mTimeBaseRunning && mUnpluggedReportedCount == 0) {
+        /**
+         * Updates the current recorded values. These are meant to be monotonically increasing
+         * and cumulative. If you are dealing with deltas, use {@link #add(long, int)}.
+         *
+         * If the values being recorded have been reset, the monotonically increasing requirement
+         * will be broken. In this case, {@link #endSample()} is automatically called and
+         * the total value of totalTime and count are recorded, starting a new monotonically
+         * increasing sample.
+         *
+         * @param totalTime total time of sample in microseconds.
+         * @param count total number of times the event being sampled occurred.
+         */
+        public void update(long totalTime, int count) {
+            if (mTimeBaseRunning && !mTrackingReportedValues) {
                 // Updating the reported value for the first time.
+                mUnpluggedReportedTotalTime = totalTime;
                 mUnpluggedReportedCount = count;
-                // If we are receiving an update update mTrackingReportedValues;
-                mTrackingReportedValues = true;
             }
+
+            mTrackingReportedValues = true;
+
+            if (totalTime < mCurrentReportedTotalTime || count < mCurrentReportedCount) {
+                endSample();
+            }
+
+            mCurrentReportedTotalTime = totalTime;
             mCurrentReportedCount = count;
         }
 
-        public void addCurrentReportedCount(int delta) {
-            updateCurrentReportedCount(mCurrentReportedCount + delta);
+        /**
+         * Adds deltaTime and deltaCount to the current sample.
+         *
+         * @param deltaTime additional time recorded since the last sampled event, in microseconds.
+         * @param deltaCount additional number of times the event being sampled occurred.
+         */
+        public void add(long deltaTime, int deltaCount) {
+            update(mCurrentReportedTotalTime + deltaTime, mCurrentReportedCount + deltaCount);
         }
 
-        public void updateCurrentReportedTotalTime(long totalTime) {
-            if (mTimeBaseRunning && mUnpluggedReportedTotalTime == 0) {
-                // Updating the reported value for the first time.
-                mUnpluggedReportedTotalTime = totalTime;
-                // If we are receiving an update update mTrackingReportedValues;
-                mTrackingReportedValues = true;
-            }
-            mCurrentReportedTotalTime = totalTime;
-        }
-
-        public void addCurrentReportedTotalTime(long delta) {
-            updateCurrentReportedTotalTime(mCurrentReportedTotalTime + delta);
-        }
-
+        @Override
         public void onTimeStarted(long elapsedRealtime, long baseUptime, long baseRealtime) {
             super.onTimeStarted(elapsedRealtime, baseUptime, baseRealtime);
             if (mTrackingReportedValues) {
@@ -1319,11 +1346,13 @@
             mTimeBaseRunning = true;
         }
 
+        @Override
         public void onTimeStopped(long elapsedRealtime, long baseUptime, long baseRealtime) {
             super.onTimeStopped(elapsedRealtime, baseUptime, baseRealtime);
             mTimeBaseRunning = false;
         }
 
+        @Override
         public void logState(Printer pw, String prefix) {
             super.logState(pw, prefix);
             pw.println(prefix + "mCurrentReportedCount=" + mCurrentReportedCount
@@ -1332,16 +1361,19 @@
                     + " mUnpluggedReportedTotalTime=" + mUnpluggedReportedTotalTime);
         }
 
+        @Override
         protected long computeRunTimeLocked(long curBatteryRealtime) {
             return mTotalTime + (mTimeBaseRunning && mTrackingReportedValues
                     ? mCurrentReportedTotalTime - mUnpluggedReportedTotalTime : 0);
         }
 
+        @Override
         protected int computeCurrentCountLocked() {
             return mCount + (mTimeBaseRunning && mTrackingReportedValues
                     ? mCurrentReportedCount - mUnpluggedReportedCount : 0);
         }
 
+        @Override
         public void writeToParcel(Parcel out, long elapsedRealtimeUs) {
             super.writeToParcel(out, elapsedRealtimeUs);
             out.writeInt(mCurrentReportedCount);
@@ -1351,12 +1383,16 @@
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
 
+        @Override
         public boolean reset(boolean detachIfReset) {
             super.reset(detachIfReset);
-            setStale();
+            mTrackingReportedValues = false;
+            mUnpluggedReportedTotalTime = 0;
+            mUnpluggedReportedCount = 0;
             return true;
         }
 
+        @Override
         public void writeSummaryFromParcelLocked(Parcel out, long batteryRealtime) {
             super.writeSummaryFromParcelLocked(out, batteryRealtime);
             out.writeLong(mCurrentReportedTotalTime);
@@ -1364,6 +1400,7 @@
             out.writeInt(mTrackingReportedValues ? 1 : 0);
         }
 
+        @Override
         public void readSummaryFromParcelLocked(Parcel in) {
             super.readSummaryFromParcelLocked(in);
             mUnpluggedReportedTotalTime = mCurrentReportedTotalTime = in.readLong();
@@ -2002,7 +2039,7 @@
     public SamplingTimer getWakeupReasonTimerLocked(String name) {
         SamplingTimer timer = mWakeupReasonStats.get(name);
         if (timer == null) {
-            timer = new SamplingTimer(mClocks, mOnBatteryTimeBase, true);
+            timer = new SamplingTimer(mClocks, mOnBatteryTimeBase);
             mWakeupReasonStats.put(name, timer);
         }
         return timer;
@@ -2015,8 +2052,7 @@
     public SamplingTimer getKernelWakelockTimerLocked(String name) {
         SamplingTimer kwlt = mKernelWakelockStats.get(name);
         if (kwlt == null) {
-            kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
-                    true /* track reported values */);
+            kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
             mKernelWakelockStats.put(name, kwlt);
         }
         return kwlt;
@@ -3125,8 +3161,7 @@
         if (mLastWakeupReason != null) {
             long deltaUptime = uptimeMs - mLastWakeupUptimeMs;
             SamplingTimer timer = getWakeupReasonTimerLocked(mLastWakeupReason);
-            timer.addCurrentReportedCount(1);
-            timer.addCurrentReportedTotalTime(deltaUptime * 1000); // time is in microseconds
+            timer.add(deltaUptime * 1000, 1); // time in in microseconds
             mLastWakeupReason = null;
         }
     }
@@ -3400,7 +3435,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);
@@ -8727,16 +8762,15 @@
 
             SamplingTimer kwlt = mKernelWakelockStats.get(name);
             if (kwlt == null) {
-                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase,
-                        true /* track reported val */);
+                kwlt = new SamplingTimer(mClocks, mOnBatteryScreenOffTimeBase);
                 mKernelWakelockStats.put(name, kwlt);
             }
-            kwlt.updateCurrentReportedCount(kws.mCount);
-            kwlt.updateCurrentReportedTotalTime(kws.mTotalTime);
+            kwlt.update(kws.mTotalTime, kws.mCount);
             kwlt.setUpdateVersion(kws.mVersion);
 
-            if (kws.mVersion != wakelockStats.kernelWakelockVersion)
-            seenNonZeroTime |= kws.mTotalTime > 0;
+            if (kws.mVersion != wakelockStats.kernelWakelockVersion) {
+                seenNonZeroTime |= kws.mTotalTime > 0;
+            }
         }
 
         int numWakelocksSetStale = 0;
@@ -8745,7 +8779,7 @@
             for (Map.Entry<String, SamplingTimer> ent : mKernelWakelockStats.entrySet()) {
                 SamplingTimer st = ent.getValue();
                 if (st.getUpdateVersion() != wakelockStats.kernelWakelockVersion) {
-                    st.setStale();
+                    st.endSample();
                     numWakelocksSetStale++;
                 }
             }
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/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index eb0c742..037ff37 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1587,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" />
 
@@ -2037,10 +2038,10 @@
     <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
         android:protectionLevel="signature|privileged" />
 
-    <!-- @SystemApi Allows but does not guarantee access to user passwords at the conclusion of add
-         account -->
-    <permission android:name="android.permission.GET_PASSWORD_PRIVILEGED"
-        android:protectionLevel="signature|privileged" />
+    <!-- Allows but does not guarantee access to user passwords at the conclusion of add account
+    @hide -->
+    <permission android:name="android.permission.GET_PASSWORD"
+        android:protectionLevel="signature" />
 
     <!-- @SystemApi Allows applications to RW to diagnostic resources.
     <p>Not for use by third-party applications. -->
@@ -2082,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"
@@ -2232,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
     -->
@@ -2279,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 -->
@@ -2396,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" />
 
@@ -2946,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/values/attrs.xml b/core/res/res/values/attrs.xml
index b85ed9c..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>
 
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 03c6048..1b286ab 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -4096,6 +4096,10 @@
 
     <!-- [CHAR_LIMIT=NONE] Data saver: Feature description -->
     <string name="data_saver_description">To help reduce data usage, Data Saver prevents some apps from sending or receiving data in the background. An app you’re currently using can access data, but may do so less frequently. This may mean, for example, that images don’t display until you tap them.</string>
+    <!-- [CHAR_LIMIT=30] Data saver: Title on first-time dialogFeature description -->
+    <string name="data_saver_enable_title">Turn on Data Saver?</string>
+    <!-- [CHAR_LIMIT=16] Data saver: Button to turn it on on first-time dialog -->
+    <string name="data_saver_enable_button">Turn on</string>
 
     <!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_minutes_summary">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index adeaa63..ccd2e92 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2102,6 +2102,8 @@
   <java-symbol type="dimen" name="timepicker_text_size_inner" />
   <java-symbol type="string" name="battery_saver_description" />
   <java-symbol type="string" name="data_saver_description" />
+  <java-symbol type="string" name="data_saver_enable_title" />
+  <java-symbol type="string" name="data_saver_enable_button" />
   <java-symbol type="string" name="zen_mode_forever" />
   <java-symbol type="string" name="zen_mode_forever_dnd" />
   <java-symbol type="string" name="zen_mode_rule_name_combination" />
@@ -2574,4 +2576,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/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
index 51d41a4..ce6879d 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryStatsSamplingTimerTest.java
@@ -21,9 +21,120 @@
 
 import junit.framework.TestCase;
 
+import org.mockito.Mockito;
+
 public class BatteryStatsSamplingTimerTest extends TestCase {
 
     @SmallTest
+    public void testSettingStalePreservesData() throws Exception {
+        final MockClocks clocks = new MockClocks();
+        final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
+                Mockito.mock(BatteryStatsImpl.TimeBase.class));
+
+        timer.onTimeStarted(100, 100, 100);
+
+        // First update is absorbed.
+        timer.update(10, 1);
+
+        timer.update(20, 2);
+
+        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+
+        timer.endSample();
+
+        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+
+        timer.onTimeStopped(200, 200, 200);
+
+        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(10, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+    }
+
+    @SmallTest
+    public void testEndSampleAndContinueWhenTimeOrCountDecreases() throws Exception {
+        final MockClocks clocks = new MockClocks();
+        final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
+        final BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks,
+                timeBase);
+
+        // First once is absorbed.
+        timer.update(10, 1);
+
+        timer.add(10, 1);
+
+        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+
+        // This is less than we currently have, so we will end the sample. Time isn't running, so
+        // nothing should happen.
+        timer.update(0, 0);
+
+        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(0, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+
+        timer.onTimeStarted(100, 100, 100);
+
+        // This should add.
+        timer.add(100, 10);
+
+        assertEquals(100, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(10, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+        // This is less than we currently have, so we should end our sample and continue with the
+        // entire amount updated here.
+        timer.update(50, 5);
+
+        assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+        timer.onTimeStopped(200, 200, 200);
+
+        assertEquals(150, timer.getTotalTimeLocked(200, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(15, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+    }
+
+    @SmallTest
+    public void testFirstUpdateIsAbsorbed() throws Exception {
+        final MockClocks clocks = new MockClocks();
+        final BatteryStatsImpl.TimeBase timeBase = Mockito.mock(BatteryStatsImpl.TimeBase.class);
+
+        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
+
+        // This should be absorbed because it is our first update and we don't know what
+        // was being counted before.
+        timer.update(10, 1);
+
+        assertEquals(0, timer.getTotalTimeLocked(10, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+        timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
+        timer.onTimeStarted(100, 100, 100);
+
+        // This should be absorbed.
+        timer.update(10, 1);
+
+        assertEquals(0, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(0, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+        // This should NOT be aborbed, since we've already done that.
+        timer.add(10, 1);
+
+        assertEquals(10, timer.getTotalTimeLocked(100, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(1, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+
+        timer.onTimeStopped(200, 200, 200);
+        timer.onTimeStarted(300, 300, 300);
+
+        // This should NOT be absorbed.
+        timer.add(10, 1);
+
+        assertEquals(20, timer.getTotalTimeLocked(300, BatteryStats.STATS_SINCE_CHARGED));
+        assertEquals(2, timer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
+    }
+
+    @SmallTest
     public void testSampleTimerSummaryParceling() throws Exception {
         final MockClocks clocks = new MockClocks();
         clocks.realtime = 0;
@@ -32,18 +143,15 @@
         final BatteryStatsImpl.TimeBase timeBase = new BatteryStatsImpl.TimeBase();
         timeBase.init(clocks.uptimeMillis(), clocks.elapsedRealtime());
 
-        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase,
-                true);
+        BatteryStatsImpl.SamplingTimer timer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
 
         // Start running on battery.
         timeBase.setRunning(true, clocks.uptimeMillis(), clocks.elapsedRealtime());
 
         // The first update on battery consumes the values as a way of starting cleanly.
-        timer.addCurrentReportedTotalTime(10);
-        timer.addCurrentReportedCount(1);
+        timer.add(10, 1);
 
-        timer.addCurrentReportedTotalTime(10);
-        timer.addCurrentReportedCount(1);
+        timer.add(10, 1);
 
         clocks.realtime = 20;
         clocks.uptime = 20;
@@ -72,14 +180,14 @@
 
         // Read the on battery summary from the parcel.
         BatteryStatsImpl.SamplingTimer unparceledTimer = new BatteryStatsImpl.SamplingTimer(
-                clocks, timeBase, true);
+                clocks, timeBase);
         unparceledTimer.readSummaryFromParcelLocked(onBatterySummaryParcel);
 
         assertEquals(10, unparceledTimer.getTotalTimeLocked(0, BatteryStats.STATS_SINCE_CHARGED));
         assertEquals(1, unparceledTimer.getCountLocked(BatteryStats.STATS_SINCE_CHARGED));
 
         // Read the off battery summary from the parcel.
-        unparceledTimer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase, true);
+        unparceledTimer = new BatteryStatsImpl.SamplingTimer(clocks, timeBase);
         unparceledTimer.readSummaryFromParcelLocked(offBatterySummaryParcel);
 
         assertEquals(10, unparceledTimer.getTotalTimeLocked(0, BatteryStats.STATS_SINCE_CHARGED));
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/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/RootsFragment.java b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
index 8bbcc30..94edd83 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/RootsFragment.java
@@ -228,10 +228,11 @@
         }
 
         public View getView(View convertView, ViewGroup parent) {
-            if (convertView == null) {
-                convertView = LayoutInflater.from(parent.getContext())
+            // Disable recycling views because 1) it's very unlikely a view can be recycled here;
+            // 2) there is no easy way for us to know with which layout id the convertView was
+            // inflated; and 3) simplicity is much appreciated at this time.
+            convertView = LayoutInflater.from(parent.getContext())
                         .inflate(mLayoutId, parent, false);
-            }
             bindView(convertView);
             return convertView;
         }
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 32fdb64..9e2b86a 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -82,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 {
@@ -191,6 +196,11 @@
         public boolean enableManagedMode() {
             return false;
         }
+
+        @Override
+        public boolean allowDragNDrop() {
+            return false;
+        }
     }
 
     /**
@@ -255,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/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index 95e36fd..3d6643d 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -44,6 +44,8 @@
 
     <!-- Toast message sent when the bugreport file could be read. -->
     <string name="bugreport_unreadable_text">Bug report file could not be read</string>
+    <!-- Toast message sent when the bugreport details could not be added to the zip file. -->
+    <string name="bugreport_add_details_to_zip_failed">Couldn\'t add bug report details to zip file</string>
 
     <!-- Title for bug reports received from dumpstate without a name. [CHAR LIMIT=30]-->
     <string name="bugreport_unnamed">unnamed</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 7023a1a..474e3e6 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -1134,6 +1134,8 @@
             addEntry(zos, "description.txt", info.description);
         } catch (IOException e) {
             Log.e(TAG, "exception zipping file " + tmpZip, e);
+            Toast.makeText(mContext, R.string.bugreport_add_details_to_zip_failed,
+                    Toast.LENGTH_LONG).show();
             return;
         } finally {
             // Make sure it only tries to add details once, even it fails the first time.
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/anim/tv_pip_onboarding_background_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_background_enter_animation.xml
new file mode 100644
index 0000000..9ab41d0
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_background_enter_animation.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<set xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <objectAnimator
+        android:propertyName="alpha"
+        android:valueFrom="0"
+        android:valueTo="0.9"
+        android:interpolator="@android:interpolator/linear"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
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/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
index 288ad1e..fe80b94 100644
--- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml
+++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
@@ -21,8 +21,13 @@
     android:id="@+id/pip_onboarding"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#B3000000"
     android:orientation="vertical">
+    <View
+        android:id="@+id/background"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:background="#000000"
+        android:alpha="0" />
 
     <ImageView
         android:id="@+id/remote"
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/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
index ebfd8ab..3b62938 100644
--- a/packages/SystemUI/res/values/integers_tv.xml
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -25,6 +25,8 @@
     <!-- Delay between the start of slide in animation for each card. -->
     <integer name="recents_home_delay">40</integer>
 
+    <!-- Delay of the onboarding animation start after it launches -->
+    <integer name="tv_pip_onboarding_anim_start_delay">1000</integer>
     <!-- Duration of the onboarding animation duration -->
     <integer name="tv_pip_onboarding_anim_duration">1000</integer>
 </resources>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index c78efe2..81fa520 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,6 +387,9 @@
     <!-- 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>
 
@@ -468,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] -->
@@ -633,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] -->
@@ -669,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] -->
@@ -1635,14 +1657,41 @@
     <!-- Accessibility label for window when QS editing is happening [CHAR LIMIT=NONE] -->
     <string name="accessibility_desc_quick_settings_edit">Quick settings editor.</string>
 
+    <!-- Accessibility label for the notification icons in the collapsed status bar. Not shown on screen [CHAR LIMIT=NONE] -->
+    <string name="accessibility_desc_notification_icon"><xliff:g name="app_name" example="Gmail">%1$s</xliff:g> notification: <xliff:g name="notification_text" example="5 new messages">%2$s</xliff:g></string>
+
     <!-- Multi-Window strings -->
     <!-- Text that gets shown on top of current activity to inform the user that the system force-resized the current activity and that things might crash/not work properly [CHAR LIMIT=NONE] -->
     <string name="dock_forced_resizable">App may not work with split-screen.</string>
     <!-- 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/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index dcd1654..b1d23d8 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -32,9 +32,9 @@
     <!-- Picture-in-Picture (PIP) onboarding screen -->
     <eat-comment />
     <!-- Title for picture-in-picture (PIP) onboarding screen to indicate that an user is in PIP mode. [CHAR LIMIT=NONE] -->
-    <string name="pip_onboarding_title">PIP mode</string>
+    <string name="pip_onboarding_title">Picture-in-picture</string>
     <!-- Description for picture-in-picture (PIP) onboarding screen to indicate that longpress HOME key to control PIP. [CHAR LIMIT=NONE] -->
-    <string name="pip_onboarding_description">To control PIP press and hold the <b>HOME</b> button on the remote</string>
+    <string name="pip_onboarding_description">This keeps your video in view until you play another one. Press and hold <b>HOME</b> to control it.</string>
     <!-- Button to close picture-in-picture (PIP) onboarding screen. -->
     <string name="pip_onboarding_button">Got it</string>
     <!-- Dismiss icon description -->
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 4a8abf7..9dc9c4c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -217,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;
@@ -230,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
@@ -263,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/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/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 9fd4b05..7379706 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -277,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;
                     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 8bf32c2..be68344 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";
@@ -1247,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);
@@ -1343,6 +1351,10 @@
         KeyboardShortcuts.toggle(mContext, deviceId);
     }
 
+    protected void dismissKeyboardShortcuts() {
+        KeyboardShortcuts.dismiss();
+    }
+
     protected void cancelPreloadingRecents() {
         if (mRecents != null) {
             mRecents.cancelPreloadingRecents();
@@ -1517,6 +1529,9 @@
              case MSG_TOGGLE_KEYBOARD_SHORTCUTS_MENU:
                   toggleKeyboardShortcuts(m.arg1);
                   break;
+             case MSG_DISMISS_KEYBOARD_SHORTCUTS_MENU:
+                  dismissKeyboardShortcuts();
+                  break;
             }
         }
     }
@@ -2099,7 +2114,7 @@
                 smallIcon,
                 n.iconLevel,
                 n.number,
-                n.tickerText);
+                StatusBarIconView.contentDescForNotification(mContext, n));
         if (!iconView.set(ic)) {
             handleNotificationError(sbn, "Couldn't create icon: " + ic);
             return null;
@@ -2268,7 +2283,7 @@
                             n.getSmallIcon(),
                             n.iconLevel,
                             n.number,
-                            n.tickerText);
+                            StatusBarIconView.contentDescForNotification(mContext, n));
                     entry.icon.setNotification(n);
                     if (!entry.icon.set(ic)) {
                         handleNotificationError(notification, "Couldn't update icon: " + ic);
@@ -2292,7 +2307,7 @@
                     n.getSmallIcon(),
                     n.iconLevel,
                     n.number,
-                    n.tickerText);
+                    StatusBarIconView.contentDescForNotification(mContext, n));
             entry.icon.setNotification(n);
             entry.icon.set(ic);
             inflateViews(entry, mStackScroller);
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/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 83f68e8..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);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
index 870447a..6d76763e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/StatusBarIconView.java
@@ -307,9 +307,9 @@
 
     private void setContentDescription(Notification notification) {
         if (notification != null) {
-            CharSequence tickerText = notification.tickerText;
-            if (!TextUtils.isEmpty(tickerText)) {
-                setContentDescription(tickerText);
+            String d = contentDescForNotification(mContext, notification);
+            if (!TextUtils.isEmpty(d)) {
+                setContentDescription(d);
             }
         }
     }
@@ -322,4 +322,12 @@
     public String getSlot() {
         return mSlot;
     }
+
+
+    public static String contentDescForNotification(Context c, Notification n) {
+        Notification.Builder builder = Notification.Builder.recoverBuilder(c, n);
+        String appName = builder.loadHeaderAppName();
+        CharSequence ticker = n.tickerText;
+        return c.getString(R.string.accessibility_desc_notification_icon, appName, ticker);
+    }
 }
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/tv/pip/PipOnboardingActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
index 398572a..9a87cfc 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -24,6 +24,7 @@
 import android.graphics.drawable.AnimationDrawable;
 import android.os.Bundle;
 import android.view.View;
+import android.view.KeyEvent;
 import android.widget.ImageView;
 
 import com.android.systemui.R;
@@ -33,6 +34,7 @@
  */
 public class PipOnboardingActivity extends Activity implements PipManager.Listener {
     private final PipManager mPipManager = PipManager.getInstance();
+    private AnimatorSet mEnterAnimator;
 
     @Override
     protected void onCreate(Bundle bundle) {
@@ -51,22 +53,25 @@
     @Override
     public void onResume() {
         super.onResume();
-        AnimatorSet enterAnimator = new AnimatorSet();
-        enterAnimator.playTogether(
+        mEnterAnimator = new AnimatorSet();
+        mEnterAnimator.playTogether(
+                loadAnimator(R.id.background, R.anim.tv_pip_onboarding_background_enter_animation),
                 loadAnimator(R.id.remote, R.anim.tv_pip_onboarding_image_enter_animation),
                 loadAnimator(R.id.remote_button, R.anim.tv_pip_onboarding_image_enter_animation),
                 loadAnimator(R.id.title, R.anim.tv_pip_onboarding_title_enter_animation),
                 loadAnimator(R.id.description,
                         R.anim.tv_pip_onboarding_description_enter_animation),
                 loadAnimator(R.id.button, R.anim.tv_pip_onboarding_button_enter_animation));
-        enterAnimator.addListener(new AnimatorListenerAdapter() {
+        mEnterAnimator.addListener(new AnimatorListenerAdapter() {
             @Override
             public void onAnimationStart(Animator animation) {
                 ImageView button = (ImageView) findViewById(R.id.remote_button);
                 ((AnimationDrawable) button.getDrawable()).start();
             }
         });
-        enterAnimator.start();
+        int delay = getResources().getInteger(R.integer.tv_pip_onboarding_anim_start_delay);
+        mEnterAnimator.setStartDelay(delay);
+        mEnterAnimator.start();
     }
 
     private Animator loadAnimator(int viewResId, int animResId) {
@@ -76,6 +81,22 @@
     }
 
     @Override
+    public boolean onKeyUp(int keyCode, KeyEvent event) {
+        if (mEnterAnimator.isStarted()) {
+            return true;
+        }
+        return super.onKeyUp(keyCode, event);
+    }
+
+    @Override
+    public boolean onKeyDown(int keyCode, KeyEvent event) {
+        if (mEnterAnimator.isStarted()) {
+            return true;
+        }
+        return super.onKeyDown(keyCode, event);
+    }
+
+    @Override
     public void onPause() {
         super.onPause();
         finish();
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/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 87dedc9..c792c11 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -2589,7 +2589,7 @@
         // Check to see if the Password should be included to the caller.
         String callerPkg = optionsIn.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
         boolean isPasswordForwardingAllowed = isPermitted(
-                callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+                callerPkg, uid, Manifest.permission.GET_PASSWORD);
 
         int usrId = UserHandle.getCallingUserId();
         long identityToken = clearCallingIdentity();
@@ -3008,7 +3008,7 @@
         // Check to see if the Password should be included to the caller.
         String callerPkg = loginOptions.getString(AccountManager.KEY_ANDROID_PACKAGE_NAME);
         boolean isPasswordForwardingAllowed = isPermitted(
-                callerPkg, uid, Manifest.permission.GET_PASSWORD_PRIVILEGED);
+                callerPkg, uid, Manifest.permission.GET_PASSWORD);
 
         long identityToken = clearCallingIdentity();
         try {
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 3b024cf..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;
@@ -17169,9 +17173,8 @@
         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)
@@ -20054,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 06d6430..3df4a61 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -3434,8 +3434,8 @@
                 mWindowManager.executeAppTransition();
                 mStackSupervisor.mWaitingVisibleActivities.add(r);
             }
-            return finishCurrentActivityLocked(r,
-                    r.visible ? FINISH_AFTER_VISIBLE : 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);
         }
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/BroadcastQueue.java b/services/core/java/com/android/server/am/BroadcastQueue.java
index bbb8bdf..1222f54 100644
--- a/services/core/java/com/android/server/am/BroadcastQueue.java
+++ b/services/core/java/com/android/server/am/BroadcastQueue.java
@@ -274,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,
diff --git a/services/core/java/com/android/server/am/NativeCrashListener.java b/services/core/java/com/android/server/am/NativeCrashListener.java
index d0973d5..e2870d8 100644
--- a/services/core/java/com/android/server/am/NativeCrashListener.java
+++ b/services/core/java/com/android/server/am/NativeCrashListener.java
@@ -49,8 +49,8 @@
     static final String DEBUGGERD_SOCKET_PATH = "/data/system/ndebugsocket";
 
     // Use a short timeout on socket operations and abandon the connection
-    // on hard errors
-    static final long SOCKET_TIMEOUT_MILLIS = 2000;  // 2 seconds
+    // on hard errors, just in case debuggerd goes out to lunch.
+    static final long SOCKET_TIMEOUT_MILLIS = 10000;  // 10 seconds
 
     final ActivityManagerService mAm;
 
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/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/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/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/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 30ba28a..8174c13 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -538,12 +538,15 @@
     }
 
     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) {
+            if (mDimLayer != null && mDimLayer.isDimming()) {
                 mDimLayer.setLayer(mService.mLayersController.getResizeDimLayer());
             }
             return false;
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index ad33b4c..037f316 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -554,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);
     }
 
@@ -1279,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 {
@@ -1303,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;
         }
@@ -1317,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/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 ff63632..0b66959 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -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() {
@@ -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;
         }
@@ -3694,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);
@@ -7498,7 +7519,7 @@
                 stack.resetAdjustedForIme(!dockVisible);
             }
             displayContent.mDividerControllerLocked.setAdjustedForIme(
-                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, null);
+                    false /*ime*/, false /*divider*/, dockVisible /*animate*/, imeWin);
         }
     }
 
@@ -8852,6 +8873,9 @@
             mWaitingForConfig = true;
             startFreezingDisplayLocked(false, 0, 0);
             mH.sendEmptyMessage(H.SEND_NEW_CONFIGURATION);
+            if (!mReconfigureOnConfigurationChanged.contains(displayContent)) {
+                mReconfigureOnConfigurationChanged.add(displayContent);
+            }
         }
 
         mWindowPlacerLocked.performSurfacePlacement();
@@ -9137,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,
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 f603995..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;
@@ -1695,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/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_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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 9f2ca59..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;
@@ -1111,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/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/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index 0922a12..27351e4 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -370,20 +370,28 @@
         }
         if (mHaveAssistData) {
             AssistDataForActivity assistData;
-            while (!mAssistData.isEmpty()) {
-                if (mPendingAssistDataCount <= 0) {
-                    Slog.e(TAG, "mPendingAssistDataCount is " + mPendingAssistDataCount);
+            if (mAssistData.isEmpty()) {
+                // We're not actually going to get any data, deliver some nothing
+                try {
+                    mSession.handleAssist(null, null, null, 0, 0);
+                } catch (RemoteException e) {
                 }
-                mPendingAssistDataCount--;
-                assistData = mAssistData.remove(0);
-                if (assistData.data == null) {
-                    try {
-                        mSession.handleAssist(null, null, null, assistData.activityIndex,
-                                assistData.activityCount);
-                    } catch (RemoteException e) {
+            } else {
+                while (!mAssistData.isEmpty()) {
+                    if (mPendingAssistDataCount <= 0) {
+                        Slog.e(TAG, "mPendingAssistDataCount is " + mPendingAssistDataCount);
                     }
-                } else {
-                    deliverSessionDataLocked(assistData);
+                    mPendingAssistDataCount--;
+                    assistData = mAssistData.remove(0);
+                    if (assistData.data == null) {
+                        try {
+                            mSession.handleAssist(null, null, null, assistData.activityIndex,
+                                    assistData.activityCount);
+                        } catch (RemoteException e) {
+                        }
+                    } else {
+                        deliverSessionDataLocked(assistData);
+                    }
                 }
             }
             if (mPendingAssistDataCount <= 0) {
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 15d76fd..e8df24e 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -16,8 +16,6 @@
 
 package android.telephony;
 
-import com.android.internal.telephony.ICarrierConfigLoader;
-
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SystemApi;
@@ -26,6 +24,8 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 
+import com.android.internal.telephony.ICarrierConfigLoader;
+
 /**
  * Provides access to telephony configuration values that are carrier-specific.
  * <p>
@@ -454,12 +454,12 @@
     /**
      * Whether cellular data is required to access visual voicemail.
      */
-    public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN = "vvm_cellular_data_required";
+    public static final String KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL = "vvm_cellular_data_required";
 
     /**
      * Whether to prefetch audio data on new voicemail arrival, defaulted to true.
      */
-    public static final String KEY_VVM_PREFETCH_BOOLEAN = "vvm_prefetch";
+    public static final String KEY_VVM_PREFETCH_BOOL = "vvm_prefetch";
 
     /**
      * The package name of the carrier's visual voicemail app to ensure that dialer visual voicemail
@@ -735,8 +735,8 @@
         sDefaults.putString(KEY_VVM_DESTINATION_NUMBER_STRING, "");
         sDefaults.putInt(KEY_VVM_PORT_NUMBER_INT, 0);
         sDefaults.putString(KEY_VVM_TYPE_STRING, "");
-        sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOLEAN, false);
-        sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN, true);
+        sDefaults.putBoolean(KEY_VVM_CELLULAR_DATA_REQUIRED_BOOL, false);
+        sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOL, true);
         sDefaults.putString(KEY_CARRIER_VVM_PACKAGE_NAME_STRING, "");
         sDefaults.putBoolean(KEY_SHOW_ICCID_IN_SIM_STATUS_BOOL, false);
         sDefaults.putBoolean(KEY_CI_ACTION_ON_SYS_UPDATE_BOOL, false);
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];
     }