Merge "PipManager: Revisit the logic for PIP close for TV app case" into nyc-dev
diff --git a/Android.mk b/Android.mk
index ae5d67e..2017404 100644
--- a/Android.mk
+++ b/Android.mk
@@ -442,8 +442,6 @@
 	telephony/java/com/android/internal/telephony/ISms.aidl \
 	telephony/java/com/android/internal/telephony/ISub.aidl \
 	telephony/java/com/android/internal/telephony/ITelephony.aidl \
-	telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl \
-	telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl \
 	telephony/java/com/android/internal/telephony/ITelephonyRegistry.aidl \
 	telephony/java/com/android/internal/telephony/IWapPushManager.aidl \
 	wifi/java/android/net/wifi/IWifiManager.aidl \
diff --git a/api/current.txt b/api/current.txt
index 8d1b450..f924b5b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -891,6 +891,7 @@
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
+    field public static final int numberPickerStyle = 16844071; // 0x1010527
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2534,6 +2535,7 @@
     field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
     field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
     field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
     field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
     field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
     field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2566,6 +2568,7 @@
     field public static final int Widget_Material_ListView = 16974448; // 0x1030270
     field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
     field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+    field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
     field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
     field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
     field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -4480,6 +4483,7 @@
     method public void startActivity(android.content.Intent, android.os.Bundle);
     method public void startActivityForResult(android.content.Intent, int);
     method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void unregisterForContextMenu(android.view.View);
   }
 
@@ -4571,6 +4575,7 @@
     method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
     method public boolean onShouldSaveFragmentState(android.app.Fragment);
     method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public boolean onUseFragmentManagerInflaterFactory();
   }
 
@@ -5897,7 +5902,7 @@
     method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
-    method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+    method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
@@ -5920,7 +5925,7 @@
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
-    method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+    method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5971,7 +5976,7 @@
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
-    method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+    method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5999,7 +6004,7 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
-    method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+    method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6313,6 +6318,8 @@
     method public static final long getMinimumPeriod();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
+    method public long getTriggerContentMaxDelay();
+    method public long getTriggerContentUpdateDelay();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isPeriodic();
     method public boolean isPersisted();
@@ -6343,6 +6350,8 @@
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+    method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+    method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
   }
 
   public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8615,6 +8624,7 @@
     field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
     field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
     field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
     field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
     field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8709,6 +8719,7 @@
     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_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -22887,6 +22898,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -34949,6 +34961,7 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
     method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/api/system-current.txt b/api/system-current.txt
index b3bac02..915ceb2 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -217,6 +217,7 @@
     field public static final java.lang.String SIGNAL_PERSISTENT_PROCESSES = "android.permission.SIGNAL_PERSISTENT_PROCESSES";
     field public static final java.lang.String STATUS_BAR = "android.permission.STATUS_BAR";
     field public static final java.lang.String STOP_APP_SWITCHES = "android.permission.STOP_APP_SWITCHES";
+    field public static final java.lang.String SUBSTITUTE_NOTIFICATION_APP_NAME = "android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME";
     field public static final java.lang.String SYSTEM_ALERT_WINDOW = "android.permission.SYSTEM_ALERT_WINDOW";
     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";
@@ -987,6 +988,7 @@
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
+    field public static final int numberPickerStyle = 16844071; // 0x1010527
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2637,6 +2639,7 @@
     field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
     field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
     field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
     field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
     field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
     field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2669,6 +2672,7 @@
     field public static final int Widget_Material_ListView = 16974448; // 0x1030270
     field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
     field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+    field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
     field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
     field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
     field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -4613,6 +4617,7 @@
     method public void startActivity(android.content.Intent, android.os.Bundle);
     method public void startActivityForResult(android.content.Intent, int);
     method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void unregisterForContextMenu(android.view.View);
   }
 
@@ -4704,6 +4709,7 @@
     method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
     method public boolean onShouldSaveFragmentState(android.app.Fragment);
     method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public boolean onUseFragmentManagerInflaterFactory();
   }
 
@@ -6040,7 +6046,7 @@
     method public java.lang.String getDeviceOwnerNameOnAnyUser();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
-    method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+    method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
@@ -6067,7 +6073,7 @@
     method public android.content.ComponentName getProfileOwner() throws java.lang.IllegalArgumentException;
     method public java.lang.String getProfileOwnerNameAsUser(int) throws java.lang.IllegalArgumentException;
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
-    method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+    method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -6121,7 +6127,7 @@
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
-    method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+    method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -6149,7 +6155,7 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
-    method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+    method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6581,6 +6587,8 @@
     method public static final long getMinimumPeriod();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
+    method public long getTriggerContentMaxDelay();
+    method public long getTriggerContentUpdateDelay();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isPeriodic();
     method public boolean isPersisted();
@@ -6611,6 +6619,8 @@
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+    method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+    method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
   }
 
   public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8934,6 +8944,7 @@
     field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
     field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
     field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
     field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
     field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -24493,6 +24504,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -37523,6 +37535,7 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
     method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/api/test-current.txt b/api/test-current.txt
index fcfe489..0c86fd1 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -891,6 +891,7 @@
     field public static final int notificationTimeout = 16843651; // 0x1010383
     field public static final int numColumns = 16843032; // 0x1010118
     field public static final int numStars = 16843076; // 0x1010144
+    field public static final int numberPickerStyle = 16844071; // 0x1010527
     field public static final int numbersBackgroundColor = 16843938; // 0x10104a2
     field public static final int numbersInnerTextColor = 16844001; // 0x10104e1
     field public static final int numbersSelectorColor = 16843939; // 0x10104a3
@@ -2534,6 +2535,7 @@
     field public static final int Widget_Material_Light_ListView = 16974513; // 0x10302b1
     field public static final int Widget_Material_Light_ListView_DropDown = 16974514; // 0x10302b2
     field public static final int Widget_Material_Light_MediaRouteButton = 16974515; // 0x10302b3
+    field public static final int Widget_Material_Light_NumberPicker = 16974557; // 0x10302dd
     field public static final int Widget_Material_Light_PopupMenu = 16974516; // 0x10302b4
     field public static final int Widget_Material_Light_PopupMenu_Overflow = 16974517; // 0x10302b5
     field public static final int Widget_Material_Light_PopupWindow = 16974518; // 0x10302b6
@@ -2566,6 +2568,7 @@
     field public static final int Widget_Material_ListView = 16974448; // 0x1030270
     field public static final int Widget_Material_ListView_DropDown = 16974449; // 0x1030271
     field public static final int Widget_Material_MediaRouteButton = 16974450; // 0x1030272
+    field public static final int Widget_Material_NumberPicker = 16974556; // 0x10302dc
     field public static final int Widget_Material_PopupMenu = 16974451; // 0x1030273
     field public static final int Widget_Material_PopupMenu_Overflow = 16974452; // 0x1030274
     field public static final int Widget_Material_PopupWindow = 16974453; // 0x1030275
@@ -4480,6 +4483,7 @@
     method public void startActivity(android.content.Intent, android.os.Bundle);
     method public void startActivityForResult(android.content.Intent, int);
     method public void startActivityForResult(android.content.Intent, int, android.os.Bundle);
+    method public void startIntentSenderForResult(android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public void unregisterForContextMenu(android.view.View);
   }
 
@@ -4571,6 +4575,7 @@
     method public void onRequestPermissionsFromFragment(android.app.Fragment, java.lang.String[], int);
     method public boolean onShouldSaveFragmentState(android.app.Fragment);
     method public void onStartActivityFromFragment(android.app.Fragment, android.content.Intent, int, android.os.Bundle);
+    method public void onStartIntentSenderFromFragment(android.app.Fragment, android.content.IntentSender, int, android.content.Intent, int, int, int, android.os.Bundle) throws android.content.IntentSender.SendIntentException;
     method public boolean onUseFragmentManagerInflaterFactory();
   }
 
@@ -5901,7 +5906,7 @@
     method public java.lang.CharSequence getDeviceOwnerLockScreenInfo();
     method public java.util.List<byte[]> getInstalledCaCerts(android.content.ComponentName);
     method public int getKeyguardDisabledFeatures(android.content.ComponentName);
-    method public java.lang.String getLongSupportMessage(android.content.ComponentName);
+    method public java.lang.CharSequence getLongSupportMessage(android.content.ComponentName);
     method public int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public int getOrganizationColor(android.content.ComponentName);
@@ -5924,7 +5929,7 @@
     method public java.util.List<java.lang.String> getPermittedAccessibilityServices(android.content.ComponentName);
     method public java.util.List<java.lang.String> getPermittedInputMethods(android.content.ComponentName);
     method public boolean getScreenCaptureDisabled(android.content.ComponentName);
-    method public java.lang.String getShortSupportMessage(android.content.ComponentName);
+    method public java.lang.CharSequence getShortSupportMessage(android.content.ComponentName);
     method public boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5975,7 +5980,7 @@
     method public boolean setKeyguardDisabled(android.content.ComponentName, boolean);
     method public void setKeyguardDisabledFeatures(android.content.ComponentName, int);
     method public void setLockTaskPackages(android.content.ComponentName, java.lang.String[]) throws java.lang.SecurityException;
-    method public void setLongSupportMessage(android.content.ComponentName, java.lang.String);
+    method public void setLongSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public void setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -6003,7 +6008,7 @@
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
     method public void setSecurityLoggingEnabled(android.content.ComponentName, boolean);
-    method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
+    method public void setShortSupportMessage(android.content.ComponentName, java.lang.CharSequence);
     method public boolean setStatusBarDisabled(android.content.ComponentName, boolean);
     method public int setStorageEncryption(android.content.ComponentName, boolean);
     method public void setSystemUpdatePolicy(android.content.ComponentName, android.app.admin.SystemUpdatePolicy);
@@ -6317,6 +6322,8 @@
     method public static final long getMinimumPeriod();
     method public int getNetworkType();
     method public android.content.ComponentName getService();
+    method public long getTriggerContentMaxDelay();
+    method public long getTriggerContentUpdateDelay();
     method public android.app.job.JobInfo.TriggerContentUri[] getTriggerContentUris();
     method public boolean isPeriodic();
     method public boolean isPersisted();
@@ -6347,6 +6354,8 @@
     method public android.app.job.JobInfo.Builder setRequiredNetworkType(int);
     method public android.app.job.JobInfo.Builder setRequiresCharging(boolean);
     method public android.app.job.JobInfo.Builder setRequiresDeviceIdle(boolean);
+    method public android.app.job.JobInfo.Builder setTriggerContentMaxDelay(long);
+    method public android.app.job.JobInfo.Builder setTriggerContentUpdateDelay(long);
   }
 
   public static final class JobInfo.TriggerContentUri implements android.os.Parcelable {
@@ -8622,6 +8631,7 @@
     field public static final java.lang.String ACTION_SENDTO = "android.intent.action.SENDTO";
     field public static final java.lang.String ACTION_SEND_MULTIPLE = "android.intent.action.SEND_MULTIPLE";
     field public static final java.lang.String ACTION_SET_WALLPAPER = "android.intent.action.SET_WALLPAPER";
+    field public static final java.lang.String ACTION_SHOW_APP_INFO = "android.intent.action.SHOW_APP_INFO";
     field public static final java.lang.String ACTION_SHUTDOWN = "android.intent.action.ACTION_SHUTDOWN";
     field public static final java.lang.String ACTION_SYNC = "android.intent.action.SYNC";
     field public static final java.lang.String ACTION_SYSTEM_TUTORIAL = "android.intent.action.SYSTEM_TUTORIAL";
@@ -8716,6 +8726,7 @@
     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_URI = "android.intent.extra.ORIGINATING_URI";
+    field public static final java.lang.String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
     field public static final java.lang.String EXTRA_PHONE_NUMBER = "android.intent.extra.PHONE_NUMBER";
     field public static final java.lang.String EXTRA_PROCESS_TEXT = "android.intent.extra.PROCESS_TEXT";
     field public static final java.lang.String EXTRA_PROCESS_TEXT_READONLY = "android.intent.extra.PROCESS_TEXT_READONLY";
@@ -22955,6 +22966,7 @@
     field public static final java.lang.String COLUMN_INTERNAL_PROVIDER_FLAG4 = "internal_provider_flag4";
     field public static final java.lang.String COLUMN_LONG_DESCRIPTION = "long_description";
     field public static final java.lang.String COLUMN_POSTER_ART_URI = "poster_art_uri";
+    field public static final java.lang.String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
     field public static final java.lang.String COLUMN_SEARCHABLE = "searchable";
     field public static final java.lang.String COLUMN_SEASON_DISPLAY_NUMBER = "season_display_number";
     field public static final deprecated java.lang.String COLUMN_SEASON_NUMBER = "season_number";
@@ -35024,6 +35036,7 @@
     method public void onDestroy();
     method public boolean[] onGetSupportedCommands(java.lang.String[]);
     method public void onHandleAssist(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent);
+    method public void onHandleAssistSecondary(android.os.Bundle, android.app.assist.AssistStructure, android.app.assist.AssistContent, int, int);
     method public void onHandleScreenshot(android.graphics.Bitmap);
     method public void onHide();
     method public boolean onKeyDown(int, android.view.KeyEvent);
diff --git a/core/java/android/animation/AnimatorSet.java b/core/java/android/animation/AnimatorSet.java
index 3385a17..e788d27 100644
--- a/core/java/android/animation/AnimatorSet.java
+++ b/core/java/android/animation/AnimatorSet.java
@@ -16,6 +16,9 @@
 
 package android.animation;
 
+import android.app.ActivityThread;
+import android.app.Application;
+import android.os.Build;
 import android.util.ArrayMap;
 import android.util.Log;
 
@@ -133,10 +136,25 @@
     // The total duration of finishing all the Animators in the set.
     private long mTotalDuration = 0;
 
+    // In pre-N releases, calling end() before start() on an animator set is no-op. But that is not
+    // consistent with the behavior for other animator types. In order to keep the behavior
+    // consistent within Animation framework, when end() is called without start(), we will start
+    // the animator set and immediately end it for N and forward.
+    private final boolean mShouldIgnoreEndWithoutStart;
+
     public AnimatorSet() {
         super();
         mNodeMap.put(mDelayAnim, mRootNode);
         mNodes.add(mRootNode);
+        // Set the flag to ignore calling end() without start() for pre-N releases
+        Application app = ActivityThread.currentApplication();
+        if (app == null || app.getApplicationInfo() == null) {
+            mShouldIgnoreEndWithoutStart = true;
+        } else if (app.getApplicationInfo().targetSdkVersion < Build.VERSION_CODES.N) {
+            mShouldIgnoreEndWithoutStart = true;
+        } else {
+            mShouldIgnoreEndWithoutStart = false;
+        }
     }
 
     /**
@@ -365,6 +383,9 @@
      */
     @Override
     public void end() {
+        if (mShouldIgnoreEndWithoutStart && !isStarted()) {
+            return;
+        }
         mTerminated = true;
         if (isStarted()) {
             endRemainingAnimations();
diff --git a/core/java/android/animation/ValueAnimator.java b/core/java/android/animation/ValueAnimator.java
index c6a5152..31035a7 100644
--- a/core/java/android/animation/ValueAnimator.java
+++ b/core/java/android/animation/ValueAnimator.java
@@ -1200,13 +1200,17 @@
     boolean animateBasedOnTime(long currentTime) {
         boolean done = false;
         if (mRunning) {
-            final float fraction = getScaledDuration() > 0 ?
-                    (float)(currentTime - mStartTime) / getScaledDuration() : 1f;
+            final long scaledDuration = getScaledDuration();
+            final float fraction = scaledDuration > 0 ?
+                    (float)(currentTime - mStartTime) / scaledDuration : 1f;
             final float lastFraction = mOverallFraction;
             final boolean newIteration = (int) fraction > (int) lastFraction;
             final boolean lastIterationFinished = (fraction >= mRepeatCount + 1) &&
                     (mRepeatCount != INFINITE);
-            if (newIteration && !lastIterationFinished) {
+            if (scaledDuration == 0) {
+                // 0 duration animator, ignore the repeat count and skip to the end
+                done = true;
+            } else if (newIteration && !lastIterationFinished) {
                 // Time to repeat
                 if (mListeners != null) {
                     int numListeners = mListeners.size();
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 7652766..f7884a7 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -4405,8 +4405,8 @@
             @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
             Bundle options) throws IntentSender.SendIntentException {
         if (mParent == null) {
-            startIntentSenderForResultInner(intent, requestCode, fillInIntent,
-                    flagsMask, flagsValues, this, options);
+            startIntentSenderForResultInner(intent, mEmbeddedID, requestCode, fillInIntent,
+                    flagsMask, flagsValues, options);
         } else if (options != null) {
             mParent.startIntentSenderFromChild(this, intent, requestCode,
                     fillInIntent, flagsMask, flagsValues, extraFlags, options);
@@ -4418,8 +4418,8 @@
         }
     }
 
-    private void startIntentSenderForResultInner(IntentSender intent, int requestCode,
-            Intent fillInIntent, int flagsMask, int flagsValues, Activity activity,
+    private void startIntentSenderForResultInner(IntentSender intent, String who, int requestCode,
+            Intent fillInIntent, int flagsMask, int flagsValues,
             Bundle options)
             throws IntentSender.SendIntentException {
         try {
@@ -4431,7 +4431,7 @@
             }
             int result = ActivityManagerNative.getDefault()
                 .startActivityIntentSender(mMainThread.getApplicationThread(), intent,
-                        fillInIntent, resolvedType, mToken, activity.mEmbeddedID,
+                        fillInIntent, resolvedType, mToken, who,
                         requestCode, flagsMask, flagsValues, options);
             if (result == ActivityManager.START_CANCELED) {
                 throw new IntentSender.SendIntentException();
@@ -4888,8 +4888,23 @@
             int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
             int extraFlags, @Nullable Bundle options)
             throws IntentSender.SendIntentException {
-        startIntentSenderForResultInner(intent, requestCode, fillInIntent,
-                flagsMask, flagsValues, child, options);
+        startIntentSenderForResultInner(intent, child.mEmbeddedID, requestCode, fillInIntent,
+                flagsMask, flagsValues, options);
+    }
+
+    /**
+     * Like {@link #startIntentSenderFromChild}, but taking a Fragment; see
+     * {@link #startIntentSenderForResult(IntentSender, int, Intent, int, int, int)}
+     * for more information.
+     *
+     * @hide
+     */
+    public void startIntentSenderFromChildFragment(Fragment child, IntentSender intent,
+            int requestCode, Intent fillInIntent, int flagsMask, int flagsValues,
+            int extraFlags, @Nullable Bundle options)
+            throws IntentSender.SendIntentException {
+        startIntentSenderForResultInner(intent, child.mWho, requestCode, fillInIntent,
+                flagsMask, flagsValues, options);
     }
 
     /**
@@ -7035,6 +7050,19 @@
         }
 
         @Override
+        public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
+                int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
+                int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+            if (mParent == null) {
+                startIntentSenderForResultInner(intent, fragment.mWho, requestCode, fillInIntent,
+                        flagsMask, flagsValues, options);
+            } else if (options != null) {
+                mParent.startIntentSenderFromChildFragment(fragment, intent, requestCode,
+                        fillInIntent, flagsMask, flagsValues, extraFlags, options);
+            }
+        }
+
+        @Override
         public void onRequestPermissionsFromFragment(Fragment fragment, String[] permissions,
                 int requestCode) {
             String who = REQUEST_PERMISSIONS_WHO_PREFIX + fragment.mWho;
diff --git a/core/java/android/app/ActivityManagerInternal.java b/core/java/android/app/ActivityManagerInternal.java
index 5116634..374c4f6 100644
--- a/core/java/android/app/ActivityManagerInternal.java
+++ b/core/java/android/app/ActivityManagerInternal.java
@@ -23,6 +23,8 @@
 
 import com.android.internal.app.IVoiceInteractor;
 
+import java.util.List;
+
 /**
  * Activity manager local system service interface.
  *
@@ -125,4 +127,10 @@
      * Callback for window manager to let activity manager know that the app transition is finished.
      */
     public abstract void notifyAppTransitionFinished();
+
+    /**
+     * Returns the top activity from each of the currently visible stacks. The first entry will be
+     * the focused activity.
+     */
+    public abstract List<IBinder> getTopVisibleActivities();
 }
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 65d48e6..7bf03de 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -2411,8 +2411,11 @@
             data.enforceInterface(IActivityManager.descriptor);
             int requestType = data.readInt();
             IResultReceiver receiver = IResultReceiver.Stub.asInterface(data.readStrongBinder());
+            Bundle receiverExtras = data.readBundle();
             IBinder activityToken = data.readStrongBinder();
-            boolean res = requestAssistContextExtras(requestType, receiver, activityToken);
+            boolean focused = data.readInt() == 1;
+            boolean res = requestAssistContextExtras(requestType, receiver, receiverExtras,
+                    activityToken, focused);
             reply.writeNoException();
             reply.writeInt(res ? 1 : 0);
             return true;
@@ -6080,13 +6083,16 @@
     }
 
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            IBinder activityToken) throws RemoteException {
+            Bundle receiverExtras,
+            IBinder activityToken, boolean focused) throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(requestType);
         data.writeStrongBinder(receiver.asBinder());
+        data.writeBundle(receiverExtras);
         data.writeStrongBinder(activityToken);
+        data.writeInt(focused ? 1 : 0);
         mRemote.transact(REQUEST_ASSIST_CONTEXT_EXTRAS_TRANSACTION, data, reply, 0);
         reply.readException();
         boolean res = reply.readInt() != 0;
diff --git a/core/java/android/app/Fragment.java b/core/java/android/app/Fragment.java
index 2a04c39..29f594f 100644
--- a/core/java/android/app/Fragment.java
+++ b/core/java/android/app/Fragment.java
@@ -23,6 +23,7 @@
 import android.content.ComponentCallbacks2;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -1116,6 +1117,20 @@
     }
 
     /**
+     * Call {@link Activity#startIntentSenderForResult(IntentSender, int, Intent, int, int, int,
+     * Bundle)} from the fragment's containing Activity.
+     */
+    public void startIntentSenderForResult(IntentSender intent, int requestCode,
+            @Nullable Intent fillInIntent, int flagsMask, int flagsValues, int extraFlags,
+            Bundle options) throws IntentSender.SendIntentException {
+        if (mHost == null) {
+            throw new IllegalStateException("Fragment " + this + " not attached to Activity");
+        }
+        mHost.onStartIntentSenderFromFragment(this, intent, requestCode, fillInIntent, flagsMask,
+                flagsValues, extraFlags, options);
+    }
+
+    /**
      * Receive the result from a previous call to
      * {@link #startActivityForResult(Intent, int)}.  This follows the
      * related Activity API as described there in
diff --git a/core/java/android/app/FragmentHostCallback.java b/core/java/android/app/FragmentHostCallback.java
index 13517e6..cf6b114 100644
--- a/core/java/android/app/FragmentHostCallback.java
+++ b/core/java/android/app/FragmentHostCallback.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.content.Intent;
+import android.content.IntentSender;
 import android.os.Bundle;
 import android.os.Handler;
 import android.util.ArrayMap;
@@ -131,6 +132,21 @@
     }
 
     /**
+     * Starts a new {@link IntentSender} from the given fragment.
+     * See {@link Activity#startIntentSender(IntentSender, Intent, int, int, int, Bundle)}.
+     */
+    public void onStartIntentSenderFromFragment(Fragment fragment, IntentSender intent,
+            int requestCode, @Nullable Intent fillInIntent, int flagsMask, int flagsValues,
+            int extraFlags, Bundle options) throws IntentSender.SendIntentException {
+        if (requestCode != -1) {
+            throw new IllegalStateException(
+                    "Starting intent sender with a requestCode requires a FragmentActivity host");
+        }
+        mContext.startIntentSender(intent, fillInIntent, flagsMask, flagsValues, extraFlags,
+                options);
+    }
+
+    /**
      * Requests permissions from the given fragment.
      * See {@link Activity#requestPermissions(String[], int)}
      */
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 8ee6fd0..6975116 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -523,7 +523,8 @@
     public Bundle getAssistContextExtras(int requestType) throws RemoteException;
 
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            IBinder activityToken) throws RemoteException;
+            Bundle receiverExtras,
+            IBinder activityToken, boolean focused) throws RemoteException;
 
     public void reportAssistContextExtras(IBinder token, Bundle extras,
             AssistStructure structure, AssistContent content, Uri referrer) throws RemoteException;
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 052874f..400a313 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -25,6 +25,8 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.ColorStateList;
 import android.graphics.Bitmap;
@@ -779,6 +781,16 @@
     /**
      * {@link #extras} key: this is the remote input history, as supplied to
      * {@link Builder#setRemoteInputHistory(CharSequence[])}.
+     *
+     * Apps can fill this through {@link Builder#setRemoteInputHistory(CharSequence[])}
+     * with the most recent inputs that have been sent through a {@link RemoteInput} of this
+     * Notification and are expected to clear it once the it is no longer relevant (e.g. for chat
+     * notifications once the other party has responded).
+     *
+     * The extra with this key is of type CharSequence[] and contains the most recent entry at
+     * the 0 index, the second most recent at the 1 index, etc.
+     *
+     * @see Builder#setRemoteInputHistory(CharSequence[])
      */
     public static final String EXTRA_REMOTE_INPUT_HISTORY = "android.remoteInputHistory";
 
@@ -960,6 +972,12 @@
      */
     public static final String EXTRA_CONTAINS_CUSTOM_VIEW = "android.contains.customView";
 
+    /**
+     * @SystemApi
+     * @hide
+     */
+    public static final String EXTRA_SUBSTITUTE_APP_NAME = "android.substName";
+
     private Icon mSmallIcon;
     private Icon mLargeIcon;
 
@@ -3269,14 +3287,38 @@
             }
         }
 
-        private void bindHeaderAppName(RemoteViews contentView) {
-            CharSequence appName = mContext.getPackageManager()
-                    .getApplicationLabel(mContext.getApplicationInfo());
-
-            if (TextUtils.isEmpty(appName)) {
-                return;
+        private String loadHeaderAppName() {
+            CharSequence name = null;
+            final PackageManager pm = mContext.getPackageManager();
+            if (mN.extras.containsKey(EXTRA_SUBSTITUTE_APP_NAME)) {
+                // only system packages which lump together a bunch of unrelated stuff
+                // may substitute a different name to make the purpose of the
+                // notification more clear. the correct package label should always
+                // be accessible via SystemUI.
+                final String pkg = mContext.getPackageName();
+                final String subName = mN.extras.getString(EXTRA_SUBSTITUTE_APP_NAME);
+                if (PackageManager.PERMISSION_GRANTED == pm.checkPermission(
+                        android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME, pkg)) {
+                    name = subName;
+                } else {
+                    Log.w(TAG, "warning: pkg "
+                            + pkg + " attempting to substitute app name '" + subName
+                            + "' without holding perm "
+                            + android.Manifest.permission.SUBSTITUTE_NOTIFICATION_APP_NAME);
+                }
             }
-            contentView.setTextViewText(R.id.app_name_text, appName);
+            if (TextUtils.isEmpty(name)) {
+                name = pm.getApplicationLabel(mContext.getApplicationInfo());
+            }
+            if (TextUtils.isEmpty(name)) {
+                // still nothing?
+                return null;
+            }
+
+            return String.valueOf(name);
+        }
+        private void bindHeaderAppName(RemoteViews contentView) {
+            contentView.setTextViewText(R.id.app_name_text, loadHeaderAppName());
             contentView.setTextColor(R.id.app_name_text, resolveContrastColor());
         }
 
diff --git a/core/java/android/app/ResourcesManager.java b/core/java/android/app/ResourcesManager.java
index 4c4f128..aef92cf 100644
--- a/core/java/android/app/ResourcesManager.java
+++ b/core/java/android/app/ResourcesManager.java
@@ -29,6 +29,7 @@
 import android.content.res.ResourcesKey;
 import android.hardware.display.DisplayManagerGlobal;
 import android.os.IBinder;
+import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.DisplayMetrics;
 import android.util.LocaleList;
@@ -430,37 +431,44 @@
             @Nullable Configuration overrideConfig,
             @NonNull CompatibilityInfo compatInfo,
             @Nullable ClassLoader classLoader) {
-        final ResourcesKey key = new ResourcesKey(
-                resDir,
-                splitResDirs,
-                overlayDirs,
-                libDirs,
-                displayId,
-                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
-                compatInfo);
-        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+                    "ResourcesManager#createBaseActivityResources");
+            final ResourcesKey key = new ResourcesKey(
+                    resDir,
+                    splitResDirs,
+                    overlayDirs,
+                    libDirs,
+                    displayId,
+                    overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                    compatInfo);
+            classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
 
-        if (DEBUG) {
-            Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
-                    + " with key=" + key);
-        }
-
-        synchronized (this) {
-            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
-                    activityToken);
-
-            if (overrideConfig != null) {
-                activityResources.overrideConfig.setTo(overrideConfig);
-            } else {
-                activityResources.overrideConfig.setToDefaults();
+            if (DEBUG) {
+                Slog.d(TAG, "createBaseActivityResources activity=" + activityToken
+                        + " with key=" + key);
             }
+
+            synchronized (this) {
+                final ActivityResources activityResources =
+                        getOrCreateActivityResourcesStructLocked(
+                                activityToken);
+
+                if (overrideConfig != null) {
+                    activityResources.overrideConfig.setTo(overrideConfig);
+                } else {
+                    activityResources.overrideConfig.setToDefaults();
+                }
+            }
+
+            // Update any existing Activity Resources references.
+            updateResourcesForActivity(activityToken, overrideConfig);
+
+            // Now request an actual Resources object.
+            return getOrCreateResources(activityToken, key, classLoader);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
-
-        // Update any existing Activity Resources references.
-        updateResourcesForActivity(activityToken, overrideConfig);
-
-        // Now request an actual Resources object.
-        return getOrCreateResources(activityToken, key, classLoader);
     }
 
     /**
@@ -490,8 +498,8 @@
             }
 
             if (activityToken != null) {
-                final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
-                        activityToken);
+                final ActivityResources activityResources =
+                        getOrCreateActivityResourcesStructLocked(activityToken);
 
                 // Clean up any dead references so they don't pile up.
                 ArrayUtils.unstableRemoveIf(activityResources.activityResources,
@@ -539,6 +547,7 @@
         final String[] systemLocales = findSystemLocales
                 ? AssetManager.getSystem().getLocales() : null;
         final String[] nonSystemLocales = resourcesImpl.getAssets().getNonSystemLocales();
+
         // Avoid checking for non-pseudo-locales if we already know there were some from a previous
         // Resources. The default value (for when hasNonSystemLocales is true) doesn't matter,
         // since mHasNonSystemLocales will also be true, and thus isPseudoLocalesOnly would not be
@@ -613,16 +622,21 @@
             @Nullable Configuration overrideConfig,
             @NonNull CompatibilityInfo compatInfo,
             @Nullable ClassLoader classLoader) {
-        final ResourcesKey key = new ResourcesKey(
-                resDir,
-                splitResDirs,
-                overlayDirs,
-                libDirs,
-                displayId,
-                overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
-                compatInfo);
-        classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
-        return getOrCreateResources(activityToken, key, classLoader);
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "ResourcesManager#getResources");
+            final ResourcesKey key = new ResourcesKey(
+                    resDir,
+                    splitResDirs,
+                    overlayDirs,
+                    libDirs,
+                    displayId,
+                    overrideConfig != null ? new Configuration(overrideConfig) : null, // Copy
+                    compatInfo);
+            classLoader = classLoader != null ? classLoader : ClassLoader.getSystemClassLoader();
+            return getOrCreateResources(activityToken, key, classLoader);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+        }
     }
 
     /**
@@ -636,93 +650,104 @@
      */
     public void updateResourcesForActivity(@NonNull IBinder activityToken,
             @Nullable Configuration overrideConfig) {
-        synchronized (this) {
-            final ActivityResources activityResources = getOrCreateActivityResourcesStructLocked(
-                    activityToken);
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+                    "ResourcesManager#updateResourcesForActivity");
+            synchronized (this) {
+                final ActivityResources activityResources =
+                        getOrCreateActivityResourcesStructLocked(activityToken);
 
-            if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
-                // They are the same, no work to do.
-                return;
-            }
-
-            // Grab a copy of the old configuration so we can create the delta's of each
-            // Resources object associated with this Activity.
-            final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
-
-            // Update the Activity's base override.
-            if (overrideConfig != null) {
-                activityResources.overrideConfig.setTo(overrideConfig);
-            } else {
-                activityResources.overrideConfig.setToDefaults();
-            }
-
-            if (DEBUG) {
-                Throwable here = new Throwable();
-                here.fillInStackTrace();
-                Slog.d(TAG, "updating resources override for activity=" + activityToken
-                        + " from oldConfig=" + Configuration.resourceQualifierString(oldConfig)
-                        + " to newConfig="
-                        + Configuration.resourceQualifierString(activityResources.overrideConfig),
-                        here);
-            }
-
-            final boolean activityHasOverrideConfig =
-                    !activityResources.overrideConfig.equals(Configuration.EMPTY);
-
-            // Rebase each Resources associated with this Activity.
-            final int refCount = activityResources.activityResources.size();
-            for (int i = 0; i < refCount; i++) {
-                WeakReference<Resources> weakResRef = activityResources.activityResources.get(i);
-                Resources resources = weakResRef.get();
-                if (resources == null) {
-                    continue;
+                if (Objects.equals(activityResources.overrideConfig, overrideConfig)) {
+                    // They are the same, no work to do.
+                    return;
                 }
 
-                // Extract the ResourcesKey that was last used to create the Resources for this
-                // activity.
-                final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
-                if (oldKey == null) {
-                    Slog.e(TAG, "can't find ResourcesKey for resources impl="
-                            + resources.getImpl());
-                    continue;
-                }
+                // Grab a copy of the old configuration so we can create the delta's of each
+                // Resources object associated with this Activity.
+                final Configuration oldConfig = new Configuration(activityResources.overrideConfig);
 
-                // Build the new override configuration for this ResourcesKey.
-                final Configuration rebasedOverrideConfig = new Configuration();
+                // Update the Activity's base override.
                 if (overrideConfig != null) {
-                    rebasedOverrideConfig.setTo(overrideConfig);
+                    activityResources.overrideConfig.setTo(overrideConfig);
+                } else {
+                    activityResources.overrideConfig.setToDefaults();
                 }
 
-                if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
-                    // Generate a delta between the old base Activity override configuration and
-                    // the actual final override configuration that was used to figure out the real
-                    // delta this Resources object wanted.
-                    Configuration overrideOverrideConfig = Configuration.generateDelta(
-                            oldConfig, oldKey.mOverrideConfiguration);
-                    rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
-                }
-
-                // Create the new ResourcesKey with the rebased override config.
-                final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir, oldKey.mSplitResDirs,
-                        oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
-                        rebasedOverrideConfig, oldKey.mCompatInfo);
-
                 if (DEBUG) {
-                    Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
-                            + " to newKey=" + newKey);
+                    Throwable here = new Throwable();
+                    here.fillInStackTrace();
+                    Slog.d(TAG, "updating resources override for activity=" + activityToken
+                            + " from oldConfig="
+                            + Configuration.resourceQualifierString(oldConfig)
+                            + " to newConfig="
+                            + Configuration.resourceQualifierString(
+                            activityResources.overrideConfig),
+                            here);
                 }
 
-                ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
-                if (resourcesImpl == null) {
-                    resourcesImpl = createResourcesImpl(newKey);
-                    mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
-                }
+                final boolean activityHasOverrideConfig =
+                        !activityResources.overrideConfig.equals(Configuration.EMPTY);
 
-                if (resourcesImpl != resources.getImpl()) {
-                    // Set the ResourcesImpl, updating it for all users of this Resources object.
-                    resources.setImpl(resourcesImpl);
+                // Rebase each Resources associated with this Activity.
+                final int refCount = activityResources.activityResources.size();
+                for (int i = 0; i < refCount; i++) {
+                    WeakReference<Resources> weakResRef = activityResources.activityResources.get(
+                            i);
+                    Resources resources = weakResRef.get();
+                    if (resources == null) {
+                        continue;
+                    }
+
+                    // Extract the ResourcesKey that was last used to create the Resources for this
+                    // activity.
+                    final ResourcesKey oldKey = findKeyForResourceImplLocked(resources.getImpl());
+                    if (oldKey == null) {
+                        Slog.e(TAG, "can't find ResourcesKey for resources impl="
+                                + resources.getImpl());
+                        continue;
+                    }
+
+                    // Build the new override configuration for this ResourcesKey.
+                    final Configuration rebasedOverrideConfig = new Configuration();
+                    if (overrideConfig != null) {
+                        rebasedOverrideConfig.setTo(overrideConfig);
+                    }
+
+                    if (activityHasOverrideConfig && oldKey.hasOverrideConfiguration()) {
+                        // Generate a delta between the old base Activity override configuration and
+                        // the actual final override configuration that was used to figure out the
+                        // real delta this Resources object wanted.
+                        Configuration overrideOverrideConfig = Configuration.generateDelta(
+                                oldConfig, oldKey.mOverrideConfiguration);
+                        rebasedOverrideConfig.updateFrom(overrideOverrideConfig);
+                    }
+
+                    // Create the new ResourcesKey with the rebased override config.
+                    final ResourcesKey newKey = new ResourcesKey(oldKey.mResDir,
+                            oldKey.mSplitResDirs,
+                            oldKey.mOverlayDirs, oldKey.mLibDirs, oldKey.mDisplayId,
+                            rebasedOverrideConfig, oldKey.mCompatInfo);
+
+                    if (DEBUG) {
+                        Slog.d(TAG, "rebasing ref=" + resources + " from oldKey=" + oldKey
+                                + " to newKey=" + newKey);
+                    }
+
+                    ResourcesImpl resourcesImpl = findResourcesImplForKeyLocked(newKey);
+                    if (resourcesImpl == null) {
+                        resourcesImpl = createResourcesImpl(newKey);
+                        mResourceImpls.put(newKey, new WeakReference<>(resourcesImpl));
+                    }
+
+                    if (resourcesImpl != resources.getImpl()) {
+                        // Set the ResourcesImpl, updating it for all users of this Resources
+                        // object.
+                        resources.setImpl(resourcesImpl);
+                    }
                 }
             }
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
     }
 
@@ -745,86 +770,95 @@
 
     public final boolean applyConfigurationToResourcesLocked(@NonNull Configuration config,
                                                              @Nullable CompatibilityInfo compat) {
-        if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
-            if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
-                    + mResConfiguration.seq + ", newSeq=" + config.seq);
-            return false;
-        }
-        int changes = mResConfiguration.updateFrom(config);
-        // Things might have changed in display manager, so clear the cached displays.
-        mDisplays.clear();
-        DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES,
+                    "ResourcesManager#applyConfigurationToResourcesLocked");
 
-        if (compat != null && (mResCompatibilityInfo == null ||
-                !mResCompatibilityInfo.equals(compat))) {
-            mResCompatibilityInfo = compat;
-            changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
-                    | ActivityInfo.CONFIG_SCREEN_SIZE
-                    | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
-        }
+            if (!mResConfiguration.isOtherSeqNewer(config) && compat == null) {
+                if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Skipping new config: curSeq="
+                        + mResConfiguration.seq + ", newSeq=" + config.seq);
+                return false;
+            }
+            int changes = mResConfiguration.updateFrom(config);
+            // Things might have changed in display manager, so clear the cached displays.
+            mDisplays.clear();
+            DisplayMetrics defaultDisplayMetrics = getDisplayMetrics();
 
-        Configuration localeAdjustedConfig = config;
-        final LocaleList configLocales = config.getLocales();
-        if (!configLocales.isEmpty()) {
-            setDefaultLocalesLocked(configLocales);
-            final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
-            if (adjustedLocales != configLocales) { // has the same result as .equals() in this case
-                // The first locale in the list was not chosen. So we create a modified
-                // configuration with the adjusted locales (which moves the chosen locale to the
-                // front).
-                localeAdjustedConfig = new Configuration();
-                localeAdjustedConfig.setTo(config);
-                localeAdjustedConfig.setLocales(adjustedLocales);
-                // Also adjust the locale list in mResConfiguration, so that the Resources created
-                // later would have the same locale list.
-                if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
-                    mResConfiguration.setLocales(adjustedLocales);
-                    changes |= ActivityInfo.CONFIG_LOCALE;
+            if (compat != null && (mResCompatibilityInfo == null ||
+                    !mResCompatibilityInfo.equals(compat))) {
+                mResCompatibilityInfo = compat;
+                changes |= ActivityInfo.CONFIG_SCREEN_LAYOUT
+                        | ActivityInfo.CONFIG_SCREEN_SIZE
+                        | ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+            }
+
+            Configuration localeAdjustedConfig = config;
+            final LocaleList configLocales = config.getLocales();
+            if (!configLocales.isEmpty()) {
+                setDefaultLocalesLocked(configLocales);
+                final LocaleList adjustedLocales = LocaleList.getAdjustedDefault();
+                if (adjustedLocales
+                        != configLocales) { // has the same result as .equals() in this case
+                    // The first locale in the list was not chosen. So we create a modified
+                    // configuration with the adjusted locales (which moves the chosen locale to the
+                    // front).
+                    localeAdjustedConfig = new Configuration();
+                    localeAdjustedConfig.setTo(config);
+                    localeAdjustedConfig.setLocales(adjustedLocales);
+                    // Also adjust the locale list in mResConfiguration, so that the Resources
+                    // created later would have the same locale list.
+                    if (!mResConfiguration.getLocales().equals(adjustedLocales)) {
+                        mResConfiguration.setLocales(adjustedLocales);
+                        changes |= ActivityInfo.CONFIG_LOCALE;
+                    }
                 }
             }
-        }
 
-        Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics, compat);
+            Resources.updateSystemConfiguration(localeAdjustedConfig, defaultDisplayMetrics,
+                    compat);
 
-        ApplicationPackageManager.configurationChanged();
-        //Slog.i(TAG, "Configuration changed in " + currentPackageName());
+            ApplicationPackageManager.configurationChanged();
+            //Slog.i(TAG, "Configuration changed in " + currentPackageName());
 
-        Configuration tmpConfig = null;
+            Configuration tmpConfig = null;
 
-        for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
-            ResourcesKey key = mResourceImpls.keyAt(i);
-            ResourcesImpl r = mResourceImpls.valueAt(i).get();
-            if (r != null) {
-                if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
-                        + r + " config to: " + localeAdjustedConfig);
-                int displayId = key.mDisplayId;
-                boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
-                DisplayMetrics dm = defaultDisplayMetrics;
-                final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
-                if (!isDefaultDisplay || hasOverrideConfiguration) {
-                    if (tmpConfig == null) {
-                        tmpConfig = new Configuration();
+            for (int i = mResourceImpls.size() - 1; i >= 0; i--) {
+                ResourcesKey key = mResourceImpls.keyAt(i);
+                ResourcesImpl r = mResourceImpls.valueAt(i).get();
+                if (r != null) {
+                    if (DEBUG || DEBUG_CONFIGURATION) Slog.v(TAG, "Changing resources "
+                            + r + " config to: " + localeAdjustedConfig);
+                    int displayId = key.mDisplayId;
+                    boolean isDefaultDisplay = (displayId == Display.DEFAULT_DISPLAY);
+                    DisplayMetrics dm = defaultDisplayMetrics;
+                    final boolean hasOverrideConfiguration = key.hasOverrideConfiguration();
+                    if (!isDefaultDisplay || hasOverrideConfiguration) {
+                        if (tmpConfig == null) {
+                            tmpConfig = new Configuration();
+                        }
+                        tmpConfig.setTo(localeAdjustedConfig);
+                        if (!isDefaultDisplay) {
+                            dm = getDisplayMetrics(displayId);
+                            applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
+                        }
+                        if (hasOverrideConfiguration) {
+                            tmpConfig.updateFrom(key.mOverrideConfiguration);
+                        }
+                        r.updateConfiguration(tmpConfig, dm, compat);
+                    } else {
+                        r.updateConfiguration(localeAdjustedConfig, dm, compat);
                     }
-                    tmpConfig.setTo(localeAdjustedConfig);
-                    if (!isDefaultDisplay) {
-                        dm = getDisplayMetrics(displayId);
-                        applyNonDefaultDisplayMetricsToConfiguration(dm, tmpConfig);
-                    }
-                    if (hasOverrideConfiguration) {
-                        tmpConfig.updateFrom(key.mOverrideConfiguration);
-                    }
-                    r.updateConfiguration(tmpConfig, dm, compat);
+                    //Slog.i(TAG, "Updated app resources " + v.getKey()
+                    //        + " " + r + ": " + r.getConfiguration());
                 } else {
-                    r.updateConfiguration(localeAdjustedConfig, dm, compat);
+                    //Slog.i(TAG, "Removing old resources " + v.getKey());
+                    mResourceImpls.removeAt(i);
                 }
-                //Slog.i(TAG, "Updated app resources " + v.getKey()
-                //        + " " + r + ": " + r.getConfiguration());
-            } else {
-                //Slog.i(TAG, "Removing old resources " + v.getKey());
-                mResourceImpls.removeAt(i);
             }
-        }
 
-        return changes != 0;
+            return changes != 0;
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
+        }
     }
 }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index d5d4ca7..cd6e572 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -532,7 +532,8 @@
             public WifiScanner createService(ContextImpl ctx) {
                 IBinder b = ServiceManager.getService(Context.WIFI_SCANNING_SERVICE);
                 IWifiScanner service = IWifiScanner.Stub.asInterface(b);
-                return new WifiScanner(ctx.getOuterContext(), service);
+                return new WifiScanner(ctx.getOuterContext(), service,
+                        ConnectivityThread.getInstanceLooper());
             }});
 
         registerService(Context.WIFI_RTT_SERVICE, RttManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index a7bb348..269089e 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -5762,7 +5762,7 @@
      * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public void setShortSupportMessage(@NonNull ComponentName admin,
-            @Nullable String message) {
+            @Nullable CharSequence message) {
         if (mService != null) {
             try {
                 mService.setShortSupportMessage(admin, message);
@@ -5776,11 +5776,11 @@
      * Called by a device admin to get the short support message.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The message set by {@link #setShortSupportMessage(ComponentName, String)} or null if
-     *         no message has been set.
+     * @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)} or
+     *         null if no message has been set.
      * @throws SecurityException if {@code admin} is not an active administrator.
      */
-    public String getShortSupportMessage(@NonNull ComponentName admin) {
+    public CharSequence getShortSupportMessage(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getShortSupportMessage(admin);
@@ -5806,7 +5806,7 @@
      * @throws SecurityException if {@code admin} is not an active administrator.
      */
     public void setLongSupportMessage(@NonNull ComponentName admin,
-            @Nullable String message) {
+            @Nullable CharSequence message) {
         if (mService != null) {
             try {
                 mService.setLongSupportMessage(admin, message);
@@ -5820,11 +5820,11 @@
      * Called by a device admin to get the long support message.
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
-     * @return The message set by {@link #setLongSupportMessage(ComponentName, String)} or null if
-     *         no message has been set.
+     * @return The message set by {@link #setLongSupportMessage(ComponentName, CharSequence)} or
+     *         null if no message has been set.
      * @throws SecurityException if {@code admin} is not an active administrator.
      */
-    public String getLongSupportMessage(@NonNull ComponentName admin) {
+    public CharSequence getLongSupportMessage(@NonNull ComponentName admin) {
         if (mService != null) {
             try {
                 return mService.getLongSupportMessage(admin);
@@ -5840,11 +5840,12 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle user id the admin is running as.
-     * @return The message set by {@link #setShortSupportMessage(ComponentName, String)}
+     * @return The message set by {@link #setShortSupportMessage(ComponentName, CharSequence)}
      *
      * @hide
      */
-    public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+    public CharSequence getShortSupportMessageForUser(@NonNull ComponentName admin,
+            int userHandle) {
         if (mService != null) {
             try {
                 return mService.getShortSupportMessageForUser(admin, userHandle);
@@ -5861,11 +5862,11 @@
      *
      * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
      * @param userHandle user id the admin is running as.
-     * @return The message set by {@link #setLongSupportMessage(ComponentName, String)}
+     * @return The message set by {@link #setLongSupportMessage(ComponentName, CharSequence)}
      *
      * @hide
      */
-    public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+    public CharSequence getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
         if (mService != null) {
             try {
                 return mService.getLongSupportMessageForUser(admin, userHandle);
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 2801b87..cba64c2 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -269,13 +269,13 @@
     String getWifiMacAddress(in ComponentName admin);
     void reboot(in ComponentName admin);
 
-    void setShortSupportMessage(in ComponentName admin, in String message);
-    String getShortSupportMessage(in ComponentName admin);
-    void setLongSupportMessage(in ComponentName admin, in String message);
-    String getLongSupportMessage(in ComponentName admin);
+    void setShortSupportMessage(in ComponentName admin, in CharSequence message);
+    CharSequence getShortSupportMessage(in ComponentName admin);
+    void setLongSupportMessage(in ComponentName admin, in CharSequence message);
+    CharSequence getLongSupportMessage(in ComponentName admin);
 
-    String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
-    String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
+    CharSequence getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+    CharSequence getLongSupportMessageForUser(in ComponentName admin, int userHandle);
 
     boolean isSeparateProfileChallengeAllowed(int userHandle);
 
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 9b4f43a..c84a0dc 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -138,12 +138,28 @@
      */
     public static final int PRIORITY_TOP_APP = 40;
 
+    /**
+     * Adjustment of {@link #getPriority} if the app has often (50% or more of the time)
+     * been running jobs.
+     * @hide
+     */
+    public static final int PRIORITY_ADJ_OFTEN_RUNNING = -40;
+
+    /**
+     * Adjustment of {@link #getPriority} if the app has always (90% or more of the time)
+     * been running jobs.
+     * @hide
+     */
+    public static final int PRIORITY_ADJ_ALWAYS_RUNNING = -80;
+
     private final int jobId;
     private final PersistableBundle extras;
     private final ComponentName service;
     private final boolean requireCharging;
     private final boolean requireDeviceIdle;
     private final TriggerContentUri[] triggerContentUris;
+    private final long triggerContentUpdateDelay;
+    private final long triggerContentMaxDelay;
     private final boolean hasEarlyConstraint;
     private final boolean hasLateConstraint;
     private final int networkType;
@@ -207,6 +223,22 @@
     }
 
     /**
+     * When triggering on content URI changes, this is the delay from when a change
+     * is detected until the job is scheduled.
+     */
+    public long getTriggerContentUpdateDelay() {
+        return triggerContentUpdateDelay;
+    }
+
+    /**
+     * When triggering on content URI changes, this is the maximum delay we will
+     * use before scheduling the job.
+     */
+    public long getTriggerContentMaxDelay() {
+        return triggerContentMaxDelay;
+    }
+
+    /**
      * One of {@link android.app.job.JobInfo#NETWORK_TYPE_ANY},
      * {@link android.app.job.JobInfo#NETWORK_TYPE_NONE}, or
      * {@link android.app.job.JobInfo#NETWORK_TYPE_UNMETERED}.
@@ -307,6 +339,8 @@
         requireCharging = in.readInt() == 1;
         requireDeviceIdle = in.readInt() == 1;
         triggerContentUris = in.createTypedArray(TriggerContentUri.CREATOR);
+        triggerContentUpdateDelay = in.readLong();
+        triggerContentMaxDelay = in.readLong();
         networkType = in.readInt();
         minLatencyMillis = in.readLong();
         maxExecutionDelayMillis = in.readLong();
@@ -330,6 +364,8 @@
         triggerContentUris = b.mTriggerContentUris != null
                 ? b.mTriggerContentUris.toArray(new TriggerContentUri[b.mTriggerContentUris.size()])
                 : null;
+        triggerContentUpdateDelay = b.mTriggerContentUpdateDelay;
+        triggerContentMaxDelay = b.mTriggerContentMaxDelay;
         networkType = b.mNetworkType;
         minLatencyMillis = b.mMinLatencyMillis;
         maxExecutionDelayMillis = b.mMaxExecutionDelayMillis;
@@ -357,6 +393,8 @@
         out.writeInt(requireCharging ? 1 : 0);
         out.writeInt(requireDeviceIdle ? 1 : 0);
         out.writeTypedArray(triggerContentUris, flags);
+        out.writeLong(triggerContentUpdateDelay);
+        out.writeLong(triggerContentMaxDelay);
         out.writeInt(networkType);
         out.writeLong(minLatencyMillis);
         out.writeLong(maxExecutionDelayMillis);
@@ -468,6 +506,8 @@
         private boolean mRequiresDeviceIdle;
         private int mNetworkType;
         private ArrayList<TriggerContentUri> mTriggerContentUris;
+        private long mTriggerContentUpdateDelay = -1;
+        private long mTriggerContentMaxDelay = -1;
         private boolean mIsPersisted;
         // One-off parameters.
         private long mMinLatencyMillis;
@@ -574,6 +614,27 @@
         }
 
         /**
+         * Set the delay (in milliseconds) from when a content change is detected until
+         * the job is scheduled.  If there are more changes during that time, the delay
+         * will be reset to start at the time of the most recent change.
+         * @param durationMs Delay after most recent content change, in milliseconds.
+         */
+        public Builder setTriggerContentUpdateDelay(long durationMs) {
+            mTriggerContentUpdateDelay = durationMs;
+            return this;
+        }
+
+        /**
+         * Set the maximum total delay (in milliseconds) that is allowed from the first
+         * time a content change is detected until the job is scheduled.
+         * @param durationMs Delay after initial content change, in milliseconds.
+         */
+        public Builder setTriggerContentMaxDelay(long durationMs) {
+            mTriggerContentMaxDelay = durationMs;
+            return this;
+        }
+
+        /**
          * Specify that this job should recur with the provided interval, not more than once per
          * period. You have no control over when within this interval this job will be executed,
          * only the guarantee that it will be executed at most once within this interval.
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 7e67e8d..831de4a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -765,6 +765,19 @@
             = "android.intent.action.APPLICATION_PREFERENCES";
 
     /**
+     * Activity Action: Launch an activity showing the app information.
+     * For applications which install other applications (such as app stores), it is recommended
+     * to handle this action for providing the app information to the user.
+     *
+     * <p>Input: {@link #EXTRA_PACKAGE_NAME} specifies the package whose information needs
+     * to be displayed.
+     * <p>Output: Nothing.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_SHOW_APP_INFO
+            = "android.intent.action.SHOW_APP_INFO";
+
+    /**
      * Represents a shortcut/live folder icon resource.
      *
      * @see Intent#ACTION_CREATE_SHORTCUT
@@ -1683,9 +1696,7 @@
      * Type: String
      * </p>
      *
-     * @hide
      */
-    @SystemApi
     public static final String EXTRA_PACKAGE_NAME = "android.intent.extra.PACKAGE_NAME";
 
     /**
diff --git a/core/java/android/content/pm/PackageUserState.java b/core/java/android/content/pm/PackageUserState.java
index 8236f55..995d2cc 100644
--- a/core/java/android/content/pm/PackageUserState.java
+++ b/core/java/android/content/pm/PackageUserState.java
@@ -87,6 +87,11 @@
     /**
      * Test if the given component is considered installed, enabled and a match
      * for the given flags.
+     *
+     * <p>
+     * Expects at least one of {@link PackageManager#MATCH_DIRECT_BOOT_AWARE} and
+     * {@link PackageManager#MATCH_DIRECT_BOOT_UNAWARE} are specified in {@code flags}.
+     * </p>
      */
     public boolean isMatch(ComponentInfo componentInfo, int flags) {
         if (!isInstalled(flags)) return false;
diff --git a/core/java/android/hardware/camera2/CaptureRequest.java b/core/java/android/hardware/camera2/CaptureRequest.java
index 79eff4f..98a8904 100644
--- a/core/java/android/hardware/camera2/CaptureRequest.java
+++ b/core/java/android/hardware/camera2/CaptureRequest.java
@@ -1590,16 +1590,16 @@
             new Key<Integer>("android.control.videoStabilizationMode", int.class);
 
     /**
-     * <p>The amount of additional sesnsitivity boost applied to output images
+     * <p>The amount of additional sensitivity boost applied to output images
      * after RAW sensor data is captured.</p>
      * <p>Some camera devices support additional digital sensitivity boosting in the
      * camera processing pipeline after sensor RAW image is captured.
      * Such a boost will be applied to YUV/JPEG format output images but will not
      * have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
-     * <p>This key is optional. Applications can assume there is no boost applied
-     * after RAW is captured if this key is not available.
-     * When this key is available, the sensitivity boost value must be within
-     * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+     * <p>This key will be <code>null</code> for devices that do not support any RAW format
+     * outputs. For devices that do support RAW format outputs, this key will always
+     * present, and if a device does not support post RAW sensitivity boost, it will
+     * list <code>100</code> in this key.</p>
      * <p>If the camera device cannot apply the exact boost requested, it will reduce the
      * boost to the nearest supported value.
      * The final boost value used will be available in the output capture result.</p>
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index 4f41e1c..8c73e6a 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -2097,16 +2097,16 @@
             new Key<Integer>("android.control.videoStabilizationMode", int.class);
 
     /**
-     * <p>The amount of additional sesnsitivity boost applied to output images
+     * <p>The amount of additional sensitivity boost applied to output images
      * after RAW sensor data is captured.</p>
      * <p>Some camera devices support additional digital sensitivity boosting in the
      * camera processing pipeline after sensor RAW image is captured.
      * Such a boost will be applied to YUV/JPEG format output images but will not
      * have effect on RAW output formats like RAW_SENSOR, RAW10, RAW12 or RAW_OPAQUE.</p>
-     * <p>This key is optional. Applications can assume there is no boost applied
-     * after RAW is captured if this key is not available.
-     * When this key is available, the sensitivity boost value must be within
-     * {@link CameraCharacteristics#CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE android.control.postRawSensitivityBoostRange}.</p>
+     * <p>This key will be <code>null</code> for devices that do not support any RAW format
+     * outputs. For devices that do support RAW format outputs, this key will always
+     * present, and if a device does not support post RAW sensitivity boost, it will
+     * list <code>100</code> in this key.</p>
      * <p>If the camera device cannot apply the exact boost requested, it will reduce the
      * boost to the nearest supported value.
      * The final boost value used will be available in the output capture result.</p>
@@ -3599,10 +3599,20 @@
 
     /**
      * <p>The shading map is a low-resolution floating-point map
-     * that lists the coefficients used to correct for vignetting, for each
-     * Bayer color channel of RAW image data.</p>
-     * <p>The least shaded section of the image should have a gain factor
-     * of 1; all other sections should have gains above 1.</p>
+     * that lists the coefficients used to correct for vignetting and color shading,
+     * for each Bayer color channel of RAW image data.</p>
+     * <p>The lens shading correction is defined as a full shading correction that
+     * corrects both color shading for the output non-RAW images. After the
+     * shading map is applied, the output non-RAW images will be flat-field images
+     * for flat scenes under uniform illumination.</p>
+     * <p>When there is no lens shading correction applied to RAW output images
+     * ({@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} <code>==</code> false), this map is a full lens
+     * shading correction map; when there is some lens shading correction applied
+     * to the RAW output image ({@link CameraCharacteristics#SENSOR_INFO_LENS_SHADING_APPLIED android.sensor.info.lensShadingApplied} <code>==</code> true),
+     * this map reports the remaining lens shading correction map that needs to be
+     * applied to get fully shading corrected images.</p>
+     * <p>For a full shading correction map, the least shaded section of the image
+     * should have a gain factor of 1; all other sections should have gains above 1.</p>
      * <p>When {@link CaptureRequest#COLOR_CORRECTION_MODE android.colorCorrection.mode} = TRANSFORM_MATRIX, the map
      * must take into account the colorCorrection settings.</p>
      * <p>The shading map is for the entire active pixel array, and is not
diff --git a/core/java/android/net/http/X509TrustManagerExtensions.java b/core/java/android/net/http/X509TrustManagerExtensions.java
index 87a0b70..e0fa63a 100644
--- a/core/java/android/net/http/X509TrustManagerExtensions.java
+++ b/core/java/android/net/http/X509TrustManagerExtensions.java
@@ -17,6 +17,7 @@
 package android.net.http;
 
 import android.annotation.SystemApi;
+import android.security.net.config.UserCertificateSource;
 
 import com.android.org.conscrypt.TrustManagerImpl;
 
@@ -43,7 +44,6 @@
     // Methods to use when mDelegate is not a TrustManagerImpl and duck typing is being used.
     private final X509TrustManager mTrustManager;
     private final Method mCheckServerTrusted;
-    private final Method mIsUserAddedCertificate;
     private final Method mIsSameTrustConfiguration;
 
     /**
@@ -57,7 +57,6 @@
             mDelegate = (TrustManagerImpl) tm;
             mTrustManager = null;
             mCheckServerTrusted = null;
-            mIsUserAddedCertificate = null;
             mIsSameTrustConfiguration = null;
             return;
         }
@@ -74,14 +73,6 @@
             throw new IllegalArgumentException("Required method"
                     + " checkServerTrusted(X509Certificate[], String, String, String) missing");
         }
-        // Check that isUserAddedCertificate is present.
-        try {
-            mIsUserAddedCertificate = tm.getClass().getMethod("isUserAddedCertificate",
-                    X509Certificate.class);
-        } catch (NoSuchMethodException e) {
-            throw new IllegalArgumentException(
-                    "Required method isUserAddedCertificate(X509Certificate) missing");
-        }
         // Get the option isSameTrustConfiguration method.
         Method isSameTrustConfiguration = null;
         try {
@@ -128,29 +119,15 @@
     /**
      * Checks whether a CA certificate is added by an user.
      *
-     * <p>Since {@link X509TrustManager#checkServerTrusted} allows its parameter {@code chain} to
+     * <p>Since {@link X509TrustManager#checkServerTrusted} may allow its parameter {@code chain} to
      * chain up to user-added CA certificates, this method can be used to perform additional
      * policies for user-added CA certificates.
      *
-     * @return {@code true} to indicate that the certificate was added by the user, {@code false}
-     * otherwise.
+     * @return {@code true} to indicate that the certificate authority exists in the user added
+     * certificate store, {@code false} otherwise.
      */
     public boolean isUserAddedCertificate(X509Certificate cert) {
-        if (mDelegate != null) {
-            return mDelegate.isUserAddedCertificate(cert);
-        } else {
-            try {
-                return (Boolean) mIsUserAddedCertificate.invoke(mTrustManager, cert);
-            } catch (IllegalAccessException e) {
-                throw new RuntimeException("Failed to call isUserAddedCertificate", e);
-            } catch (InvocationTargetException e) {
-                if (e.getCause() instanceof RuntimeException) {
-                    throw (RuntimeException) e.getCause();
-                } else {
-                    throw new RuntimeException("isUserAddedCertificate failed", e.getCause());
-                }
-            }
-        }
+        return UserCertificateSource.getInstance().findBySubjectAndPublicKey(cert) != null;
     }
 
     /**
diff --git a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
index c6fcb2d..a491ffc 100644
--- a/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
+++ b/core/java/android/net/metrics/ConnectivityServiceChangeEvent.java
@@ -25,18 +25,40 @@
 public class ConnectivityServiceChangeEvent extends IpConnectivityEvent implements Parcelable {
     public static final String TAG = "ConnectivityServiceChangeEvent";
 
-    private int mNetId;
+    // The ID of the network that has become the new default or NETID_UNSET if none.
+    private final int mNetId;
+    // The list of transport types of the new default network, for example TRANSPORT_WIFI, as
+    // defined in NetworkCapabilities.java.
+    private final int[] mTransportTypes;
+    // The ID of the network that was the default before or NETID_UNSET if none.
+    private final int mPrevNetId;
+    // Whether the previous network had IPv4/IPv6 connectivity.
+    private final boolean mPrevIPv4;
+    private final boolean mPrevIPv6;
 
-    public ConnectivityServiceChangeEvent(int netId) {
+    public ConnectivityServiceChangeEvent(int netId, int[] transportTypes,
+                int prevNetId, boolean prevIPv4, boolean prevIPv6) {
         mNetId = netId;
+        mTransportTypes = transportTypes;
+        mPrevNetId = prevNetId;
+        mPrevIPv4 = prevIPv4;
+        mPrevIPv6 = prevIPv6;
     }
 
     public ConnectivityServiceChangeEvent(Parcel in) {
         mNetId = in.readInt();
+        mTransportTypes = in.createIntArray();
+        mPrevNetId = in.readInt();
+        mPrevIPv4 = (in.readByte() > 0);
+        mPrevIPv6 = (in.readByte() > 0);
     }
 
     public void writeToParcel(Parcel out, int flags) {
         out.writeInt(mNetId);
+        out.writeIntArray(mTransportTypes);
+        out.writeInt(mPrevNetId);
+        out.writeByte(mPrevIPv4 ? (byte) 1 : (byte) 0);
+        out.writeByte(mPrevIPv6 ? (byte) 1 : (byte) 0);
     }
 
     public static final Parcelable.Creator<ConnectivityServiceChangeEvent> CREATOR
@@ -50,8 +72,10 @@
         }
     };
 
-    public static void logEvent(int netId) {
+    public static void logEvent(int netId, int[] transportTypes,
+            int prevNetId, boolean prevIPv4, boolean prevIPv6) {
         IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_CONSRV_DEFAULT_NET_CHANGE,
-                new ConnectivityServiceChangeEvent(netId));
+                new ConnectivityServiceChangeEvent(
+                        netId, transportTypes, prevNetId, prevIPv4, prevIPv6));
     }
 };
diff --git a/core/java/android/net/metrics/DhcpErrorEvent.java b/core/java/android/net/metrics/DhcpErrorEvent.java
new file mode 100644
index 0000000..3869823
--- /dev/null
+++ b/core/java/android/net/metrics/DhcpErrorEvent.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide} Event class used to record error events when parsing DHCP response packets.
+ */
+public class DhcpErrorEvent extends IpConnectivityEvent implements Parcelable {
+    public static final String TAG = "DhcpErrorEvent";
+
+    public static final int L2_ERROR   = 1;
+    public static final int L3_ERROR   = 2;
+    public static final int L4_ERROR   = 3;
+    public static final int DHCP_ERROR = 4;
+    public static final int MISC_ERROR = 5;
+
+    public static final int L2_TOO_SHORT               = makeErrorCode(L2_ERROR, 1);
+    public static final int L2_WRONG_ETH_TYPE          = makeErrorCode(L2_ERROR, 2);
+
+    public static final int L3_TOO_SHORT               = makeErrorCode(L3_ERROR, 1);
+    public static final int L3_NOT_IPV4                = makeErrorCode(L3_ERROR, 2);
+    public static final int L3_INVALID_IP              = makeErrorCode(L3_ERROR, 3);
+
+    public static final int L4_NOT_UDP                 = makeErrorCode(L4_ERROR, 1);
+    public static final int L4_WRONG_PORT              = makeErrorCode(L4_ERROR, 2);
+
+    public static final int BOOTP_TOO_SHORT            = makeErrorCode(DHCP_ERROR, 1);
+    public static final int DHCP_BAD_MAGIC_COOKIE      = makeErrorCode(DHCP_ERROR, 2);
+    public static final int DHCP_INVALID_OPTION_LENGTH = makeErrorCode(DHCP_ERROR, 3);
+    public static final int DHCP_NO_MSG_TYPE           = makeErrorCode(DHCP_ERROR, 4);
+    public static final int DHCP_UNKNOWN_MSG_TYPE      = makeErrorCode(DHCP_ERROR, 5);
+
+    public static final int BUFFER_UNDERFLOW           = makeErrorCode(MISC_ERROR, 1);
+
+    // error code byte format (MSB to LSB):
+    // byte 0: error type
+    // byte 1: error subtype
+    // byte 2: unused
+    // byte 3: optional code
+    public final int errorCode;
+
+    private DhcpErrorEvent(int errorCode) {
+        this.errorCode = errorCode;
+    }
+
+    private DhcpErrorEvent(Parcel in) {
+        this.errorCode = in.readInt();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeInt(errorCode);
+    }
+
+    public static final Parcelable.Creator<DhcpErrorEvent> CREATOR
+        = new Parcelable.Creator<DhcpErrorEvent>() {
+        public DhcpErrorEvent createFromParcel(Parcel in) {
+            return new DhcpErrorEvent(in);
+        }
+
+        public DhcpErrorEvent[] newArray(int size) {
+            return new DhcpErrorEvent[size];
+        }
+    };
+
+    public static void logEvent(int errorCode) {
+        IpConnectivityEvent.logEvent(IPCE_DHCP_PARSE_ERROR, new DhcpErrorEvent(errorCode));
+    }
+
+    public static void logEvent(int errorCode, int option) {
+        logEvent((0xFFFF0000 & errorCode) | (0xFF & option));
+    }
+
+    private static int makeErrorCode(int type, int subtype) {
+        return (type << 24) | ((0xFF & subtype) << 16);
+    }
+}
diff --git a/core/java/android/net/metrics/IpConnectivityEvent.java b/core/java/android/net/metrics/IpConnectivityEvent.java
index ec42890..59c1cfe 100644
--- a/core/java/android/net/metrics/IpConnectivityEvent.java
+++ b/core/java/android/net/metrics/IpConnectivityEvent.java
@@ -28,14 +28,17 @@
     // DHCP = DhcpClient
     // NETMON = NetworkMonitorEvent
     // CONSRV = ConnectivityServiceEvent
+    // IPMGR = IpManager
     public static final String TAG = "IpConnectivityEvent";
     public static final int IPCE_IPRM_BASE = 0*1024;
     public static final int IPCE_DHCP_BASE = 1*1024;
     public static final int IPCE_NETMON_BASE = 2*1024;
     public static final int IPCE_CONSRV_BASE = 3*1024;
+    public static final int IPCE_IPMGR_BASE = 4*1024;
 
     public static final int IPCE_IPRM_PROBE_RESULT = IPCE_IPRM_BASE + 0;
     public static final int IPCE_IPRM_MESSAGE_RECEIVED = IPCE_IPRM_BASE + 1;
+    public static final int IPCE_IPRM_REACHABILITY_LOST = IPCE_IPRM_BASE + 2;
     public static final int IPCE_DHCP_RECV_ERROR = IPCE_DHCP_BASE + 0;
     public static final int IPCE_DHCP_PARSE_ERROR = IPCE_DHCP_BASE + 1;
     public static final int IPCE_DHCP_TIMEOUT = IPCE_DHCP_BASE + 2;
@@ -43,6 +46,9 @@
     public static final int IPCE_NETMON_STATE_CHANGE = IPCE_NETMON_BASE + 0;
     public static final int IPCE_NETMON_CHECK_RESULT = IPCE_NETMON_BASE + 1;
     public static final int IPCE_CONSRV_DEFAULT_NET_CHANGE = IPCE_CONSRV_BASE + 0;
+    public static final int IPCE_IPMGR_PROVISIONING_OK = IPCE_IPMGR_BASE + 0;
+    public static final int IPCE_IPMGR_PROVISIONING_FAIL = IPCE_IPMGR_BASE + 1;
+    public static final int IPCE_IPMGR_COMPLETE_LIFECYCLE = IPCE_IPMGR_BASE + 2;
 
     private static ConnectivityMetricsLogger mMetricsLogger = new ConnectivityMetricsLogger();
 
diff --git a/core/java/android/net/metrics/IpManagerEvent.java b/core/java/android/net/metrics/IpManagerEvent.java
new file mode 100644
index 0000000..6328ccb
--- /dev/null
+++ b/core/java/android/net/metrics/IpManagerEvent.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpManagerEvent extends IpConnectivityEvent implements Parcelable {
+    private String mIfName;
+    private long mDurationMs;
+
+    public IpManagerEvent(String ifName, long duration) {
+        mIfName = ifName;
+        mDurationMs = duration;
+    }
+
+    public IpManagerEvent(Parcel in) {
+        mIfName = in.readString();
+        mDurationMs = in.readLong();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mIfName);
+        out.writeLong(mDurationMs);
+    }
+
+    public static final Parcelable.Creator<IpManagerEvent> CREATOR
+        = new Parcelable.Creator<IpManagerEvent>() {
+        public IpManagerEvent createFromParcel(Parcel in) {
+            return new IpManagerEvent(in);
+        }
+
+        public IpManagerEvent[] newArray(int size) {
+            return new IpManagerEvent[size];
+        }
+    };
+
+    public static void logEvent(int eventType, String ifName, long durationMs) {
+        IpConnectivityEvent.logEvent(eventType, new IpManagerEvent(ifName, durationMs));
+    }
+};
diff --git a/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
new file mode 100644
index 0000000..0f14210
--- /dev/null
+++ b/core/java/android/net/metrics/IpReachabilityMonitorLostEvent.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.net.metrics;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+/**
+ * {@hide}
+ */
+public class IpReachabilityMonitorLostEvent extends IpConnectivityEvent
+        implements Parcelable {
+    private String mIfName;
+
+    public IpReachabilityMonitorLostEvent(String ifName) {
+        mIfName = ifName;
+    }
+
+    public IpReachabilityMonitorLostEvent(Parcel in) {
+        mIfName = in.readString();
+    }
+
+    public void writeToParcel(Parcel out, int flags) {
+        out.writeString(mIfName);
+    }
+
+    public static final Parcelable.Creator<IpReachabilityMonitorLostEvent> CREATOR
+        = new Parcelable.Creator<IpReachabilityMonitorLostEvent>() {
+        public IpReachabilityMonitorLostEvent createFromParcel(Parcel in) {
+            return new IpReachabilityMonitorLostEvent(in);
+        }
+
+        public IpReachabilityMonitorLostEvent[] newArray(int size) {
+            return new IpReachabilityMonitorLostEvent[size];
+        }
+    };
+
+    public static void logEvent(String ifName) {
+        IpConnectivityEvent.logEvent(IpConnectivityEvent.IPCE_IPRM_REACHABILITY_LOST,
+                new IpReachabilityMonitorLostEvent(ifName));
+    }
+};
diff --git a/core/java/android/security/net/config/NetworkSecurityTrustManager.java b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
index 3c292ca..d9cc82a 100644
--- a/core/java/android/security/net/config/NetworkSecurityTrustManager.java
+++ b/core/java/android/security/net/config/NetworkSecurityTrustManager.java
@@ -115,15 +115,6 @@
         return trustedChain;
     }
 
-    /**
-     * Check if the provided certificate is a user added certificate authority.
-     * This is required by android.net.http.X509TrustManagerExtensions.
-     */
-    public boolean isUserAddedCertificate(X509Certificate cert) {
-        // TODO: Figure out the right way to handle this, and if it is still even used.
-        return false;
-    }
-
     private void checkPins(List<X509Certificate> chain) throws CertificateException {
         PinSet pinSet = mNetworkSecurityConfig.getPins();
         if (pinSet.pins.isEmpty()
diff --git a/core/java/android/security/net/config/RootTrustManager.java b/core/java/android/security/net/config/RootTrustManager.java
index 859e022..2a30f11 100644
--- a/core/java/android/security/net/config/RootTrustManager.java
+++ b/core/java/android/security/net/config/RootTrustManager.java
@@ -131,15 +131,6 @@
         return config.getTrustManager().checkServerTrusted(certs, authType, hostname);
     }
 
-    /**
-     * Check if the provided certificate is a user added certificate authority.
-     * This is required by android.net.http.X509TrustManagerExtensions.
-     */
-    public boolean isUserAddedCertificate(X509Certificate cert) {
-        // TODO: Figure out the right way to handle this, and if it is still even used.
-        return false;
-    }
-
     @Override
     public X509Certificate[] getAcceptedIssuers() {
         // getAcceptedIssuers is meant to be used to determine which trust anchors the server will
diff --git a/core/java/android/service/carrier/CarrierIdentifier.java b/core/java/android/service/carrier/CarrierIdentifier.java
index 495fea6..a70c24d 100644
--- a/core/java/android/service/carrier/CarrierIdentifier.java
+++ b/core/java/android/service/carrier/CarrierIdentifier.java
@@ -105,6 +105,18 @@
         out.writeString(mGid2);
     }
 
+    @Override
+    public String toString() {
+      return "CarrierIdentifier{"
+          + "mcc=" + mMcc
+          + ",mnc=" + mMnc
+          + ",spn=" + mSpn
+          + ",imsi=" + mImsi
+          + ",gid1=" + mGid1
+          + ",gid2=" + mGid2
+          + "}";
+    }
+
     /** @hide */
     public void readFromParcel(Parcel in) {
         mMcc = in.readString();
diff --git a/core/java/android/service/voice/IVoiceInteractionSession.aidl b/core/java/android/service/voice/IVoiceInteractionSession.aidl
index dbc28f7..78e6bc3 100644
--- a/core/java/android/service/voice/IVoiceInteractionSession.aidl
+++ b/core/java/android/service/voice/IVoiceInteractionSession.aidl
@@ -30,7 +30,8 @@
 oneway interface IVoiceInteractionSession {
     void show(in Bundle sessionArgs, int flags, IVoiceInteractionSessionShowCallback showCallback);
     void hide();
-    void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content);
+    void handleAssist(in Bundle assistData, in AssistStructure structure, in AssistContent content,
+                      int index, int count);
     void handleScreenshot(in Bitmap screenshot);
     void taskStarted(in Intent intent, int taskId);
     void taskFinished(in Intent intent, int taskId);
diff --git a/core/java/android/service/voice/VoiceInteractionSession.java b/core/java/android/service/voice/VoiceInteractionSession.java
index 6ff9fe7..e354ab3 100644
--- a/core/java/android/service/voice/VoiceInteractionSession.java
+++ b/core/java/android/service/voice/VoiceInteractionSession.java
@@ -77,7 +77,7 @@
  */
 public class VoiceInteractionSession implements KeyEvent.Callback, ComponentCallbacks2 {
     static final String TAG = "VoiceInteractionSession";
-    static final boolean DEBUG = true;
+    static final boolean DEBUG = false;
 
     /**
      * Flag received in {@link #onShow}: originator requested that the session be started with
@@ -110,6 +110,16 @@
      */
     public static final int SHOW_SOURCE_ACTIVITY = 1<<4;
 
+    // Keys for Bundle values
+    /** @hide */
+    public static final String KEY_DATA = "data";
+    /** @hide */
+    public static final String KEY_STRUCTURE = "structure";
+    /** @hide */
+    public static final String KEY_CONTENT = "content";
+    /** @hide */
+    public static final String KEY_RECEIVER_EXTRAS = "receiverExtras";
+
     final Context mContext;
     final HandlerCaller mHandlerCaller;
 
@@ -229,7 +239,7 @@
 
         @Override
         public void handleAssist(final Bundle data, final AssistStructure structure,
-                final AssistContent content) {
+                final AssistContent content, final int index, final int count) {
             // We want to pre-warm the AssistStructure before handing it off to the main
             // thread.  We also want to do this on a separate thread, so that if the app
             // is for some reason slow (due to slow filling in of async children in the
@@ -247,8 +257,9 @@
                             failure = e;
                         }
                     }
-                    mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOO(MSG_HANDLE_ASSIST,
-                            data, failure == null ? structure : null, failure, content));
+                    mHandlerCaller.sendMessage(mHandlerCaller.obtainMessageOOOOII(MSG_HANDLE_ASSIST,
+                            data, failure == null ? structure : null, failure, content,
+                            index, count));
                 }
             };
             retriever.start();
@@ -831,9 +842,16 @@
                 case MSG_HANDLE_ASSIST:
                     args = (SomeArgs)msg.obj;
                     if (DEBUG) Log.d(TAG, "onHandleAssist: data=" + args.arg1
-                            + " structure=" + args.arg2 + " content=" + args.arg3);
-                    doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
-                            (Throwable) args.arg3, (AssistContent) args.arg4);
+                            + " structure=" + args.arg2 + " content=" + args.arg3
+                            + " activityIndex=" + args.argi5 + " activityCount=" + args.argi6);
+                    if (args.argi5 == 0) {
+                        doOnHandleAssist((Bundle) args.arg1, (AssistStructure) args.arg2,
+                                (Throwable) args.arg3, (AssistContent) args.arg4);
+                    } else {
+                        doOnHandleAssistSecondary((Bundle) args.arg1, (AssistStructure) args.arg2,
+                                (Throwable) args.arg3, (AssistContent) args.arg4,
+                                args.argi5, args.argi6);
+                    }
                     break;
                 case MSG_HANDLE_SCREENSHOT:
                     if (DEBUG) Log.d(TAG, "onHandleScreenshot: " + msg.obj);
@@ -1320,6 +1338,14 @@
         onHandleAssist(data, structure, content);
     }
 
+    void doOnHandleAssistSecondary(Bundle data, AssistStructure structure, Throwable failure,
+            AssistContent content, int index, int count) {
+        if (failure != null) {
+            onAssistStructureFailure(failure);
+        }
+        onHandleAssistSecondary(data, structure, content, index, count);
+    }
+
     /**
      * Called when there has been a failure transferring the {@link AssistStructure} to
      * the assistant.  This may happen, for example, if the data is too large and results
@@ -1356,6 +1382,45 @@
     }
 
     /**
+     * Called to receive data from other applications that the user was or is interacting with,
+     * that are currently on the screen in a multi-window display environment, not including the
+     * currently focused activity. This could be
+     * a free-form window, a picture-in-picture window, or another window in a split-screen display.
+     * <p>
+     * This method is very similar to
+     * {@link #onHandleAssist} except that it is called
+     * for additional non-focused activities along with an index and count that indicates
+     * which additional activity the data is for. {@code index} will be between 1 and
+     * {@code count}-1 and this method is called once for each additional window, in no particular
+     * order. The {@code count} indicates how many windows to expect assist data for, including the
+     * top focused activity, which continues to be returned via {@link #onHandleAssist}.
+     * <p>
+     * To be responsive to assist requests, process assist data as soon as it is received,
+     * without waiting for all queued activities to return assist data.
+     *
+     * @param data Arbitrary data supplied by the app through
+     * {@link android.app.Activity#onProvideAssistData Activity.onProvideAssistData}.
+     * May be null if assist data has been disabled by the user or device policy.
+     * @param structure If available, the structure definition of all windows currently
+     * displayed by the app.  May be null if assist data has been disabled by the user
+     * or device policy; will be an empty stub if the application has disabled assist
+     * by marking its window as secure.
+     * @param content Additional content data supplied by the app through
+     * {@link android.app.Activity#onProvideAssistContent Activity.onProvideAssistContent}.
+     * May be null if assist data has been disabled by the user or device policy; will
+     * not be automatically filled in with data from the app if the app has marked its
+     * window as secure.
+     * @param index the index of the additional activity that this data
+     *        is for.
+     * @param count the total number of additional activities for which the assist data is being
+     *        returned, including the focused activity that is returned via
+     *        {@link #onHandleAssist}.
+     */
+    public void onHandleAssistSecondary(@Nullable Bundle data, @Nullable AssistStructure structure,
+            @Nullable AssistContent content, int index, int count) {
+    }
+
+    /**
      * Called to receive a screenshot of what the user was currently viewing when an assist
      * session is started.  May be null if screenshots are disabled by the user, policy,
      * or application.  If the original show request did not specify
diff --git a/core/java/android/speech/tts/TextToSpeechService.java b/core/java/android/speech/tts/TextToSpeechService.java
index 1eaa7cf..9b238ce 100644
--- a/core/java/android/speech/tts/TextToSpeechService.java
+++ b/core/java/android/speech/tts/TextToSpeechService.java
@@ -457,8 +457,17 @@
     private class SynthHandler extends Handler {
         private SpeechItem mCurrentSpeechItem = null;
 
-        private ArrayList<Object> mFlushedObjects = new ArrayList<Object>();
-        private boolean mFlushAll;
+        // When a message with QUEUE_FLUSH arrives we add the caller identity to the List and when a
+        // message with QUEUE_DESTROY arrives we increment mFlushAll. Then a message is added to the
+        // handler queue that removes the caller identify from the list and decrements the mFlushAll
+        // counter. This is so that when a message is processed and the caller identity is in the
+        // list or mFlushAll is not zero, we know that the message should be flushed.
+        // It's important that mFlushedObjects is a List and not a Set, and that mFlushAll is an
+        // int and not a bool. This is because when multiple messages arrive with QUEUE_FLUSH or
+        // QUEUE_DESTROY, we want to keep flushing messages until we arrive at the last QUEUE_FLUSH
+        // or QUEUE_DESTROY message.
+        private List<Object> mFlushedObjects = new ArrayList<>();
+        private int mFlushAll = 0;
 
         public SynthHandler(Looper looper) {
             super(looper);
@@ -467,7 +476,7 @@
         private void startFlushingSpeechItems(Object callerIdentity) {
             synchronized (mFlushedObjects) {
                 if (callerIdentity == null) {
-                    mFlushAll = true;
+                    mFlushAll += 1;
                 } else {
                     mFlushedObjects.add(callerIdentity);
                 }
@@ -476,7 +485,7 @@
         private void endFlushingSpeechItems(Object callerIdentity) {
             synchronized (mFlushedObjects) {
                 if (callerIdentity == null) {
-                    mFlushAll = false;
+                    mFlushAll -= 1;
                 } else {
                     mFlushedObjects.remove(callerIdentity);
                 }
@@ -484,7 +493,7 @@
         }
         private boolean isFlushed(SpeechItem speechItem) {
             synchronized (mFlushedObjects) {
-                return mFlushAll || mFlushedObjects.contains(speechItem.getCallerIdentity());
+                return mFlushAll > 0 || mFlushedObjects.contains(speechItem.getCallerIdentity());
             }
         }
 
diff --git a/core/java/android/text/StaticLayout.java b/core/java/android/text/StaticLayout.java
index 94ce57a..239f2d0 100644
--- a/core/java/android/text/StaticLayout.java
+++ b/core/java/android/text/StaticLayout.java
@@ -683,7 +683,7 @@
                 // interface.
                 int leftLen = mLeftIndents == null ? 0 : mLeftIndents.length;
                 int rightLen = mRightIndents == null ? 0 : mRightIndents.length;
-                int indentsLen = Math.max(1, Math.min(leftLen, rightLen) - mLineCount);
+                int indentsLen = Math.max(1, Math.max(leftLen, rightLen) - mLineCount);
                 int[] indents = new int[indentsLen];
                 for (int i = 0; i < indentsLen; i++) {
                     int leftMargin = mLeftIndents == null ? 0 :
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index c4ed94f..206ba16 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -485,15 +485,25 @@
     }
 
     /**
-     * Stops any rendering into the surface. Use this if it is unclear whether
+     * Halts any current rendering into the surface. Use this if it is unclear whether
      * or not the surface used by the HardwareRenderer will be changing. It
-     * Suspends any rendering into the surface, but will not do any destruction
+     * Suspends any rendering into the surface, but will not do any destruction.
+     *
+     * Any subsequent draws will override the pause, resuming normal operation.
      */
     boolean pauseSurface(Surface surface) {
         return nPauseSurface(mNativeProxy, surface);
     }
 
     /**
+     * Hard stops or resumes rendering into the surface. This flag is used to
+     * determine whether or not it is safe to use the given surface *at all*
+     */
+    void setStopped(boolean stopped) {
+        nSetStopped(mNativeProxy, stopped);
+    }
+
+    /**
      * Destroys all hardware rendering resources associated with the specified
      * view hierarchy.
      *
@@ -992,6 +1002,7 @@
     private static native void nInitialize(long nativeProxy, Surface window);
     private static native void nUpdateSurface(long nativeProxy, Surface window);
     private static native boolean nPauseSurface(long nativeProxy, Surface window);
+    private static native void nSetStopped(long nativeProxy, boolean stopped);
     private static native void nSetup(long nativeProxy, int width, int height,
             float lightRadius, int ambientShadowAlpha, int spotShadowAlpha);
     private static native void nSetLightCenter(long nativeProxy,
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 307e700..8a6b5da 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -15742,8 +15742,10 @@
             return;
         }
 
-        // Destroy any previous software drawing cache if needed
-        if (mLayerType == LAYER_TYPE_SOFTWARE) {
+        if (layerType != LAYER_TYPE_SOFTWARE) {
+            // Destroy any previous software drawing cache if present
+            // NOTE: even if previous layer type is HW, we do this to ensure we've cleaned up
+            // drawing cache created in View#draw when drawing to a SW canvas.
             destroyDrawingCache();
         }
 
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 44b92e1..e9ca623 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -549,8 +549,7 @@
                 // Compute surface insets required to draw at specified Z value.
                 // TODO: Use real shadow insets for a constant max Z.
                 if (!attrs.hasManualSurfaceInsets) {
-                    final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
-                    attrs.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+                    attrs.setSurfaceInsets(view, false /*manual*/, true /*preservePrevious*/);
                 }
 
                 CompatibilityInfo compatibilityInfo = mDisplayAdjustments.getCompatibilityInfo();
@@ -883,10 +882,12 @@
             }
             mWindowAttributes.privateFlags |= compatibleWindowFlag;
 
-            // Restore old surface insets.
-            mWindowAttributes.surfaceInsets.set(
-                    oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
-            mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+            if (mWindowAttributes.preservePreviousSurfaceInsets) {
+                // Restore old surface insets.
+                mWindowAttributes.surfaceInsets.set(
+                        oldInsetLeft, oldInsetTop, oldInsetRight, oldInsetBottom);
+                mWindowAttributes.hasManualSurfaceInsets = oldHasManualSurfaceInsets;
+            }
 
             applyKeepScreenOnFlag(mWindowAttributes);
 
@@ -1079,13 +1080,16 @@
     void setWindowStopped(boolean stopped) {
         if (mStopped != stopped) {
             mStopped = stopped;
+            final ThreadedRenderer renderer = mAttachInfo.mHardwareRenderer;
+            if (renderer != null) {
+                if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle() + " set to " + mStopped);
+                renderer.setStopped(mStopped);
+            }
             if (!mStopped) {
                 scheduleTraversals();
             } else {
-                if (mAttachInfo.mHardwareRenderer != null) {
-                    if (DEBUG_DRAW) Log.d(mTag, "WindowStopped on " + getTitle());
-                    mAttachInfo.mHardwareRenderer.updateSurface(null);
-                    mAttachInfo.mHardwareRenderer.destroyHardwareResources(mView);
+                if (renderer != null) {
+                    renderer.destroyHardwareResources(mView);
                 }
             }
         }
@@ -2555,6 +2559,7 @@
 
             if (mAttachInfo.mHardwareRenderer != null) {
                 mAttachInfo.mHardwareRenderer.fence();
+                mAttachInfo.mHardwareRenderer.setStopped(mStopped);
             }
 
             if (LOCAL_LOGV) {
@@ -2704,6 +2709,13 @@
                 // shortly before the draw commands get send to the renderer.
                 final boolean updated = updateContentDrawBounds();
 
+                if (mReportNextDraw) {
+                    // report next draw overrides setStopped()
+                    // This value is re-sync'd to the value of mStopped
+                    // in the handling of mReportNextDraw post-draw.
+                    mAttachInfo.mHardwareRenderer.setStopped(false);
+                }
+
                 mAttachInfo.mHardwareRenderer.draw(mView, mAttachInfo, this);
 
                 if (updated) {
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 584233c..89e146b 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -1482,6 +1482,16 @@
         public boolean hasManualSurfaceInsets;
 
         /**
+         * Whether the previous surface insets should be used vs. what is currently set. When set
+         * to {@code true}, the view root will ignore surfaces insets in this object and use what
+         * it currently has.
+         *
+         * @see #surfaceInsets
+         * @hide
+         */
+        public boolean preservePreviousSurfaceInsets = true;
+
+        /**
          * The desired bitmap format.  May be one of the constants in
          * {@link android.graphics.PixelFormat}.  Default is OPAQUE.
          */
@@ -1716,6 +1726,16 @@
          */
         public CharSequence accessibilityTitle;
 
+        /**
+         * Sets a timeout in milliseconds before which the window will be removed
+         * by the window manager. Useful for transient notifications like toasts
+         * so we don't have to rely on client cooperation to ensure the window
+         * is removed. Must be specified at window creation time.
+         *
+         * @hide
+         */
+        public long removeTimeoutMilliseconds = -1;
+
         public LayoutParams() {
             super(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
             type = TYPE_APPLICATION;
@@ -1764,13 +1784,23 @@
                 title = "";
 
             mTitle = TextUtils.stringOrSpannedString(title);
-            accessibilityTitle = mTitle;
         }
 
         public final CharSequence getTitle() {
             return mTitle != null ? mTitle : "";
         }
 
+        /**
+         * Sets the surface insets based on the elevation (visual z position) of the input view.
+         * @hide
+         */
+        public final void setSurfaceInsets(View view, boolean manual, boolean preservePrevious) {
+            final int surfaceInset = (int) Math.ceil(view.getZ() * 2);
+            surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
+            hasManualSurfaceInsets = manual;
+            preservePreviousSurfaceInsets = preservePrevious;
+        }
+
         /** @hide */
         @SystemApi
         public final void setUserActivityTimeout(long timeout) {
@@ -1822,9 +1852,11 @@
             out.writeInt(surfaceInsets.right);
             out.writeInt(surfaceInsets.bottom);
             out.writeInt(hasManualSurfaceInsets ? 1 : 0);
+            out.writeInt(preservePreviousSurfaceInsets ? 1 : 0);
             out.writeInt(needsMenuKey);
             out.writeInt(accessibilityIdOfAnchor);
             TextUtils.writeToParcel(accessibilityTitle, out, parcelableFlags);
+            out.writeLong(removeTimeoutMilliseconds);
         }
 
         public static final Parcelable.Creator<LayoutParams> CREATOR
@@ -1874,9 +1906,11 @@
             surfaceInsets.right = in.readInt();
             surfaceInsets.bottom = in.readInt();
             hasManualSurfaceInsets = in.readInt() != 0;
+            preservePreviousSurfaceInsets = in.readInt() != 0;
             needsMenuKey = in.readInt();
             accessibilityIdOfAnchor = in.readInt();
             accessibilityTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
+            removeTimeoutMilliseconds = in.readLong();
         }
 
         @SuppressWarnings({"PointlessBitwiseExpression"})
@@ -2075,6 +2109,11 @@
                 changes |= SURFACE_INSETS_CHANGED;
             }
 
+            if (preservePreviousSurfaceInsets != o.preservePreviousSurfaceInsets) {
+                preservePreviousSurfaceInsets = o.preservePreviousSurfaceInsets;
+                changes |= SURFACE_INSETS_CHANGED;
+            }
+
             if (needsMenuKey != o.needsMenuKey) {
                 needsMenuKey = o.needsMenuKey;
                 changes |= NEEDS_MENU_KEY_CHANGED;
@@ -2092,6 +2131,9 @@
                 changes |= ACCESSIBILITY_TITLE_CHANGED;
             }
 
+            // This can't change, it's only set at window creation time.
+            removeTimeoutMilliseconds = o.removeTimeoutMilliseconds;
+
             return changes;
         }
 
@@ -2200,11 +2242,15 @@
                 sb.append(" userActivityTimeout=").append(userActivityTimeout);
             }
             if (surfaceInsets.left != 0 || surfaceInsets.top != 0 || surfaceInsets.right != 0 ||
-                    surfaceInsets.bottom != 0 || hasManualSurfaceInsets) {
+                    surfaceInsets.bottom != 0 || hasManualSurfaceInsets
+                    || !preservePreviousSurfaceInsets) {
                 sb.append(" surfaceInsets=").append(surfaceInsets);
                 if (hasManualSurfaceInsets) {
                     sb.append(" (manual)");
                 }
+                if (!preservePreviousSurfaceInsets) {
+                    sb.append(" (!preservePreviousSurfaceInsets)");
+                }
             }
             if (needsMenuKey != NEEDS_MENU_UNSET) {
                 sb.append(" needsMenuKey=");
diff --git a/core/java/android/view/accessibility/AccessibilityNodeInfo.java b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
index 02d2a8b..c1076e7 100644
--- a/core/java/android/view/accessibility/AccessibilityNodeInfo.java
+++ b/core/java/android/view/accessibility/AccessibilityNodeInfo.java
@@ -3842,7 +3842,15 @@
          */
         public static RangeInfo obtain(int type, float min, float max, float current) {
             RangeInfo info = sPool.acquire();
-            return (info != null) ? info : new RangeInfo(type, min, max, current);
+            if (info == null) {
+                return new RangeInfo(type, min, max, current);
+            }
+
+            info.mType = type;
+            info.mMin = min;
+            info.mMax = max;
+            info.mCurrent = current;
+            return info;
         }
 
         /**
diff --git a/core/java/android/webkit/WebViewFactory.java b/core/java/android/webkit/WebViewFactory.java
index 0ac5731..f13cbae 100644
--- a/core/java/android/webkit/WebViewFactory.java
+++ b/core/java/android/webkit/WebViewFactory.java
@@ -18,13 +18,14 @@
 
 import android.annotation.SystemApi;
 import android.app.ActivityManagerInternal;
+import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
 import android.app.Application;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.res.XmlResourceParser;
+import android.content.pm.Signature;
 import android.os.Build;
 import android.os.Process;
 import android.os.RemoteException;
@@ -32,27 +33,21 @@
 import android.os.StrictMode;
 import android.os.SystemProperties;
 import android.os.Trace;
-import android.provider.Settings;
-import android.provider.Settings.Secure;
 import android.text.TextUtils;
 import android.util.AndroidRuntimeException;
+import android.util.ArraySet;
 import android.util.Log;
 
-import com.android.internal.util.XmlUtils;
 import com.android.server.LocalServices;
 
 import dalvik.system.VMRuntime;
 
 import java.io.File;
 import java.io.IOException;
-import java.util.ArrayList;
 import java.util.Arrays;
-import java.util.List;
 import java.util.zip.ZipEntry;
 import java.util.zip.ZipFile;
 
-import org.xmlpull.v1.XmlPullParserException;
-
 /**
  * Top level factory, used creating all the main WebView implementation classes.
  *
@@ -192,52 +187,126 @@
         }
     }
 
+    /**
+     * Returns true if the signatures match, false otherwise
+     */
+    private static boolean signaturesEquals(Signature[] s1, Signature[] s2) {
+        if (s1 == null) {
+            return s2 == null;
+        }
+        if (s2 == null) return false;
+
+        ArraySet<Signature> set1 = new ArraySet<>();
+        for(Signature signature : s1) {
+            set1.add(signature);
+        }
+        ArraySet<Signature> set2 = new ArraySet<>();
+        for(Signature signature : s2) {
+            set2.add(signature);
+        }
+        return set1.equals(set2);
+    }
+
+    // Throws MissingWebViewPackageException on failure
+    private static void verifyPackageInfo(PackageInfo chosen, PackageInfo toUse) {
+        if (!chosen.packageName.equals(toUse.packageName)) {
+            throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+                    + "packageName mismatch, expected: "
+                    + chosen.packageName + " actual: " + toUse.packageName);
+        }
+        if (chosen.versionCode > toUse.versionCode) {
+            throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+                    + "version code mismatch, expected: " + chosen.versionCode
+                    + " actual: " + toUse.versionCode);
+        }
+        if (getWebViewLibrary(toUse.applicationInfo) == null) {
+            throw new MissingWebViewPackageException("Tried to load an invalid WebView provider: "
+                    + toUse.packageName);
+        }
+        if (!signaturesEquals(chosen.signatures, toUse.signatures)) {
+            throw new MissingWebViewPackageException("Failed to verify WebView provider, "
+                    + "signature mismatch");
+        }
+    }
+
+    private static Context getWebViewContextAndSetProvider() {
+        Application initialApplication = AppGlobals.getInitialApplication();
+        try {
+            WebViewProviderResponse response = null;
+            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+                    "WebViewUpdateService.waitForAndGetProvider()");
+            try {
+                response = getUpdateService().waitForAndGetProvider();
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+            }
+            if (response.status != LIBLOAD_SUCCESS) {
+                throw new MissingWebViewPackageException("Failed to load WebView provider: "
+                        + getWebViewPreparationErrorReason(response.status));
+            }
+            // Register to be killed before fetching package info - so that we will be
+            // killed if the package info goes out-of-date.
+            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "ActivityManager.addPackageDependency()");
+            try {
+                ActivityManagerNative.getDefault().addPackageDependency(
+                        response.packageInfo.packageName);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+            }
+            // Fetch package info and verify it against the chosen package
+            PackageInfo newPackageInfo = null;
+            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getPackageInfo()");
+            try {
+                newPackageInfo = initialApplication.getPackageManager().getPackageInfo(
+                    response.packageInfo.packageName,
+                    PackageManager.GET_SHARED_LIBRARY_FILES
+                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
+                    // Make sure that we fetch the current provider even if its not
+                    // installed for the current user
+                    | PackageManager.MATCH_UNINSTALLED_PACKAGES
+                    // Fetch signatures for verification
+                    | PackageManager.GET_SIGNATURES
+                    // Get meta-data for meta data flag verification
+                    | PackageManager.GET_META_DATA);
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+            }
+
+            // Validate the newly fetched package info, throws MissingWebViewPackageException on
+            // failure
+            verifyPackageInfo(response.packageInfo, newPackageInfo);
+
+            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
+                    "initialApplication.createApplicationContext");
+            try {
+                // Construct an app context to load the Java code into the current app.
+                Context webViewContext = initialApplication.createApplicationContext(
+                        newPackageInfo.applicationInfo,
+                        Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
+                sPackageInfo = response.packageInfo;
+                return webViewContext;
+            } finally {
+                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
+            }
+        } catch (RemoteException | PackageManager.NameNotFoundException e) {
+            throw new MissingWebViewPackageException("Failed to load WebView provider: " + e);
+        }
+    }
+
     private static Class<WebViewFactoryProvider> getProviderClass() {
+        Context webViewContext = null;
+        Application initialApplication = AppGlobals.getInitialApplication();
+
         try {
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
-                    "WebViewFactory.waitForProviderAndSetPackageInfo()");
+                    "WebViewFactory.getWebViewContextAndSetProvider()");
             try {
-                // First fetch the package info so we can log the webview package version.
-                int res = waitForProviderAndSetPackageInfo();
-                if (res != LIBLOAD_SUCCESS) {
-                    throw new MissingWebViewPackageException(
-                            "Failed to load WebView provider, error: "
-                            + getWebViewPreparationErrorReason(res));
-                }
+                webViewContext = getWebViewContextAndSetProvider();
             } finally {
                 Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
             }
             Log.i(LOGTAG, "Loading " + sPackageInfo.packageName + " version " +
-                sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
-
-            Application initialApplication = AppGlobals.getInitialApplication();
-            Context webViewContext = null;
-            Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "PackageManager.getApplicationInfo()");
-            try {
-                // Construct a package context to load the Java code into the current app.
-                // This is done as early as possible since by constructing a package context we
-                // register the WebView package as a dependency for the current application so that
-                // when the WebView package is updated this application will be killed.
-                ApplicationInfo applicationInfo =
-                    initialApplication.getPackageManager().getApplicationInfo(
-                        sPackageInfo.packageName, PackageManager.GET_SHARED_LIBRARY_FILES
-                        | PackageManager.MATCH_DEBUG_TRIAGED_MISSING
-                        // make sure that we fetch the current provider even if its not installed
-                        // for the current user
-                        | PackageManager.MATCH_UNINSTALLED_PACKAGES);
-                Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW,
-                        "initialApplication.createApplicationContext");
-                try {
-                    webViewContext = initialApplication.createApplicationContext(applicationInfo,
-                            Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY);
-                } finally {
-                    Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-                }
-            } catch (PackageManager.NameNotFoundException e) {
-                throw new MissingWebViewPackageException(e);
-            } finally {
-                Trace.traceEnd(Trace.TRACE_TAG_WEBVIEW);
-            }
+                    sPackageInfo.versionName + " (code " + sPackageInfo.versionCode + ")");
 
             Trace.traceBegin(Trace.TRACE_TAG_WEBVIEW, "WebViewFactory.getChromiumProviderClass()");
             try {
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 0d8d8ed..bb883ea 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1290,9 +1290,7 @@
 
         // We may wrap that in another view, so we'll need to manually specify
         // the surface insets.
-        final int surfaceInset = (int) Math.ceil(mBackgroundView.getZ() * 2);
-        p.surfaceInsets.set(surfaceInset, surfaceInset, surfaceInset, surfaceInset);
-        p.hasManualSurfaceInsets = true;
+        p.setSurfaceInsets(mBackgroundView, true /*manual*/, true /*preservePrevious*/);
 
         mPopupViewInitialLayoutDirectionInherited =
                 (mContentView.getRawLayoutDirection() == View.LAYOUT_DIRECTION_INHERIT);
@@ -1514,6 +1512,24 @@
         outParams.x = drawingLocation[0] + xOffset;
         outParams.y = drawingLocation[1] + anchorHeight + yOffset;
 
+        // Let the window manager know to align the top to y.
+        outParams.gravity = Gravity.LEFT | Gravity.TOP;
+        outParams.width = width;
+        outParams.height = height;
+
+        // If width or height is unspecified. We can leave it to the window manager to match
+        // to the parent size, but for our local purposes of calculating positioning, we need
+        // to fill in real width and height values.
+        final Rect displayFrame = new Rect();
+        anchor.getWindowVisibleDisplayFrame(displayFrame);
+        if (width < 0) {
+            width = displayFrame.right - displayFrame.left;
+        }
+        if (height < 0) {
+            height = displayFrame.bottom - displayFrame.top;
+        }
+
+
         // If we need to adjust for gravity RIGHT, align to the bottom-right
         // corner of the anchor (still accounting for offsets).
         final int hgrav = Gravity.getAbsoluteGravity(gravity, anchor.getLayoutDirection())
@@ -1522,17 +1538,9 @@
             outParams.x -= width - anchorWidth;
         }
 
-        // Let the window manager know to align the top to y.
-        outParams.gravity = Gravity.LEFT | Gravity.TOP;
-        outParams.width = width;
-        outParams.height = height;
-
         final int[] screenLocation = mTmpScreenLocation;
         anchor.getLocationOnScreen(screenLocation);
 
-        final Rect displayFrame = new Rect();
-        anchor.getWindowVisibleDisplayFrame(displayFrame);
-
         // First, attempt to fit the popup vertically without resizing.
         final boolean fitsVertical = tryFitVertical(outParams, yOffset, height,
                 anchorHeight, drawingLocation[1], screenLocation[1], displayFrame.top,
@@ -1581,7 +1589,7 @@
             return true;
         }
 
-        final int spaceAbove = displayFrameTop + anchorTopInScreen - anchorHeight;
+        final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
         if (height <= spaceAbove) {
             // Move everything up.
             if (mOverlapAnchor) {
@@ -2116,10 +2124,10 @@
 
         // If an explicit width/height has not specified, use the most recent
         // explicitly specified value (either from setWidth/Height or update).
-        if (width == -1) {
+        if (width < 0) {
             width = mWidth;
         }
-        if (height == -1) {
+        if (height < 0) {
             height = mHeight;
         }
 
diff --git a/core/java/android/widget/ProgressBar.java b/core/java/android/widget/ProgressBar.java
index e9fa26c..9c9784b 100644
--- a/core/java/android/widget/ProgressBar.java
+++ b/core/java/android/widget/ProgressBar.java
@@ -1347,6 +1347,13 @@
 
         if (d instanceof LayerDrawable) {
             d = ((LayerDrawable) d).findDrawableByLayerId(id);
+            if (d == null) {
+                // If we can't find the requested layer, fall back to setting
+                // the level of the entire drawable. This will break if
+                // progress is set on multiple elements, but the theme-default
+                // drawable will always have all layer IDs present.
+                d = mCurrentDrawable;
+            }
         }
 
         if (d != null) {
diff --git a/core/java/android/widget/SimpleMonthView.java b/core/java/android/widget/SimpleMonthView.java
index ee716df..1a81d20 100644
--- a/core/java/android/widget/SimpleMonthView.java
+++ b/core/java/android/widget/SimpleMonthView.java
@@ -849,10 +849,12 @@
         mEnabledDayStart = MathUtils.constrain(enabledDayStart, 1, mDaysInMonth);
         mEnabledDayEnd = MathUtils.constrain(enabledDayEnd, mEnabledDayStart, mDaysInMonth);
 
+        updateMonthYearLabel();
+        updateDayOfWeekLabels();
+
         // Invalidate cached accessibility information.
         mTouchHelper.invalidateRoot();
-
-        updateMonthYearLabel();
+        invalidate();
 
         if (DEBUG_WRONG_DATE) {
             Log.d(LOG_TAG, "mMonth = " + mMonth);
diff --git a/core/java/android/widget/Toast.java b/core/java/android/widget/Toast.java
index 207f675..7762675 100644
--- a/core/java/android/widget/Toast.java
+++ b/core/java/android/widget/Toast.java
@@ -163,6 +163,7 @@
      */
     public void setDuration(@Duration int duration) {
         mDuration = duration;
+        mTN.mDuration = duration;
     }
 
     /**
@@ -342,7 +343,7 @@
         };
 
         private final WindowManager.LayoutParams mParams = new WindowManager.LayoutParams();
-        final Handler mHandler = new Handler();    
+        final Handler mHandler = new Handler();
 
         int mGravity;
         int mX, mY;
@@ -352,9 +353,13 @@
 
         View mView;
         View mNextView;
+        int mDuration;
 
         WindowManager mWM;
 
+        static final long SHORT_DURATION_TIMEOUT = 5000;
+        static final long LONG_DURATION_TIMEOUT = 1000;
+
         TN() {
             // XXX This should be changed to use a Dialog, with a Theme.Toast
             // defined that sets up the layout params appropriately.
@@ -417,6 +422,8 @@
                 mParams.verticalMargin = mVerticalMargin;
                 mParams.horizontalMargin = mHorizontalMargin;
                 mParams.packageName = packageName;
+                mParams.removeTimeoutMilliseconds = mDuration ==
+                    Toast.LENGTH_LONG ? LONG_DURATION_TIMEOUT : SHORT_DURATION_TIMEOUT;
                 if (mView.getParent() != null) {
                     if (localLOGV) Log.v(TAG, "REMOVE! " + mView + " in " + this);
                     mWM.removeView(mView);
diff --git a/core/java/com/android/internal/app/ResolverActivity.java b/core/java/com/android/internal/app/ResolverActivity.java
index 3fc02a7..085e159 100644
--- a/core/java/com/android/internal/app/ResolverActivity.java
+++ b/core/java/com/android/internal/app/ResolverActivity.java
@@ -668,12 +668,19 @@
                 && mAdapter.mOrigResolveList != null) {
             // Build a reasonable intent filter, based on what matched.
             IntentFilter filter = new IntentFilter();
-            String action = intent.getAction();
+            Intent filterIntent;
 
+            if (intent.getSelector() != null) {
+                filterIntent = intent.getSelector();
+            } else {
+                filterIntent = intent;
+            }
+
+            String action = filterIntent.getAction();
             if (action != null) {
                 filter.addAction(action);
             }
-            Set<String> categories = intent.getCategories();
+            Set<String> categories = filterIntent.getCategories();
             if (categories != null) {
                 for (String cat : categories) {
                     filter.addCategory(cat);
@@ -682,9 +689,9 @@
             filter.addCategory(Intent.CATEGORY_DEFAULT);
 
             int cat = ri.match & IntentFilter.MATCH_CATEGORY_MASK;
-            Uri data = intent.getData();
+            Uri data = filterIntent.getData();
             if (cat == IntentFilter.MATCH_CATEGORY_TYPE) {
-                String mimeType = intent.resolveType(this);
+                String mimeType = filterIntent.resolveType(this);
                 if (mimeType != null) {
                     try {
                         filter.addDataType(mimeType);
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index bbefcb5..10afdb8 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -1745,6 +1745,9 @@
         }
 
         public void add(String name, T obj) {
+            if (name == null) {
+                name = "";
+            }
             mMap.put(name, obj);
             if (OVERFLOW_NAME.equals(name)) {
                 mCurOverflow = obj;
@@ -1776,6 +1779,9 @@
         }
 
         public T startObject(String name) {
+            if (name == null) {
+                name = "";
+            }
             T obj = mMap.get(name);
             if (obj != null) {
                 return obj;
@@ -1825,6 +1831,9 @@
         }
 
         public T stopObject(String name) {
+            if (name == null) {
+                name = "";
+            }
             T obj = mMap.get(name);
             if (obj != null) {
                 return obj;
diff --git a/core/java/com/android/internal/os/HandlerCaller.java b/core/java/com/android/internal/os/HandlerCaller.java
index 113768e..c26fc3a 100644
--- a/core/java/com/android/internal/os/HandlerCaller.java
+++ b/core/java/com/android/internal/os/HandlerCaller.java
@@ -209,6 +209,18 @@
         return mH.obtainMessage(what, 0, 0, args);
     }
 
+    public Message obtainMessageOOOOII(int what, Object arg1, Object arg2,
+            Object arg3, Object arg4, int arg5, int arg6) {
+        SomeArgs args = SomeArgs.obtain();
+        args.arg1 = arg1;
+        args.arg2 = arg2;
+        args.arg3 = arg3;
+        args.arg4 = arg4;
+        args.argi5 = arg5;
+        args.argi6 = arg6;
+        return mH.obtainMessage(what, 0, 0, args);
+    }
+
     public Message obtainMessageIIII(int what, int arg1, int arg2,
             int arg3, int arg4) {
         SomeArgs args = SomeArgs.obtain();
@@ -218,7 +230,7 @@
         args.argi4 = arg4;
         return mH.obtainMessage(what, 0, 0, args);
     }
-    
+
     public Message obtainMessageIIIIII(int what, int arg1, int arg2,
             int arg3, int arg4, int arg5, int arg6) {
         SomeArgs args = SomeArgs.obtain();
@@ -230,7 +242,7 @@
         args.argi6 = arg6;
         return mH.obtainMessage(what, 0, 0, args);
     }
-    
+
     public Message obtainMessageIIIIO(int what, int arg1, int arg2,
             int arg3, int arg4, Object arg5) {
         SomeArgs args = SomeArgs.obtain();
diff --git a/core/java/com/android/internal/policy/PhoneWindow.java b/core/java/com/android/internal/policy/PhoneWindow.java
index d2ff9bc..fe63267 100644
--- a/core/java/com/android/internal/policy/PhoneWindow.java
+++ b/core/java/com/android/internal/policy/PhoneWindow.java
@@ -1403,10 +1403,12 @@
     @Override
     public final void setElevation(float elevation) {
         mElevation = elevation;
+        final WindowManager.LayoutParams attrs = getAttributes();
         if (mDecor != null) {
             mDecor.setElevation(elevation);
+            attrs.setSurfaceInsets(mDecor, true /*manual*/, false /*preservePrevious*/);
         }
-        dispatchWindowAttributesChanged(getAttributes());
+        dispatchWindowAttributesChanged(attrs);
     }
 
     @Override
diff --git a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
index ddca51f..5cb307f 100644
--- a/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
+++ b/core/java/com/android/internal/view/menu/CascadingMenuPopup.java
@@ -347,14 +347,21 @@
         final LayoutInflater inflater = LayoutInflater.from(mContext);
         final MenuAdapter adapter = new MenuAdapter(menu, inflater, mOverflowOnly);
 
-        // Apply "force show icon" setting; if the menu being shown is the top level menu, apply the
-        // setting set on this CascadingMenuPopup by its creating code. If it's a submenu, or if no
-        // "force" setting was explicitly set, determine the setting by examining the items.
+        // Apply "force show icon" setting. There are 4 cases:
+        // (1) This is the top level menu. Only add spacing for icons if forced.
+        // (2) This is a submenu. Add spacing if any of the visible menu items has an icon.
+        // (3) This is a top level menu that is not an overflow menu. Add spacing if any of the
+        //     visible menu items has an icon.
+        // (4) This is an overflow menu or a top level menu that doesn't have "force" set.
+        //     Don't allow spacing.
         if (!isShowing() && mForceShowIcon) {
-            adapter.setForceShowIcon(mForceShowIcon);
-        } else {
-            adapter.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(menu));
+          // Case 1
+          adapter.setForceShowIcon(true);
+        } else if (isShowing() || !isShowing() && !mForceShowIcon && !mOverflowOnly) {
+          // Case 2 or 3
+          adapter.setForceShowIcon(MenuPopup.shouldPreserveIconSpacing(menu));
         }
+        // Case 4: Else, don't allow spacing for icons.
 
         final int menuWidth = measureIndividualMenuWidth(adapter, null, mContext, mMenuMaxWidth);
         final MenuPopupWindow popupWindow = createPopupWindow();
@@ -734,4 +741,4 @@
             return window.getListView();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/core/java/com/android/internal/view/menu/MenuPopup.java b/core/java/com/android/internal/view/menu/MenuPopup.java
index 16e4156..10bd66f 100644
--- a/core/java/com/android/internal/view/menu/MenuPopup.java
+++ b/core/java/com/android/internal/view/menu/MenuPopup.java
@@ -187,6 +187,11 @@
     /**
      * Returns whether icon spacing needs to be preserved for the given menu, based on whether any
      * of its items contains an icon.
+     *
+     * NOTE: This should only be used for non-overflow-only menus, because this method does not
+     * take into account whether the menu items are being shown as part of the popup or or being
+     * shown as actions in the action bar.
+     *
      * @param menu
      * @return Whether to preserve icon spacing.
      */
diff --git a/core/java/com/android/internal/widget/ILockSettings.aidl b/core/java/com/android/internal/widget/ILockSettings.aidl
index 21c4d12..b2fc2bb 100644
--- a/core/java/com/android/internal/widget/ILockSettings.aidl
+++ b/core/java/com/android/internal/widget/ILockSettings.aidl
@@ -43,4 +43,5 @@
     void unregisterStrongAuthTracker(in IStrongAuthTracker tracker);
     void requireStrongAuth(int strongAuthReason, int userId);
     void systemReady();
+    void userPresent(int userId);
 }
diff --git a/core/java/com/android/internal/widget/LockPatternUtils.java b/core/java/com/android/internal/widget/LockPatternUtils.java
index bceeaca..d9b6329 100644
--- a/core/java/com/android/internal/widget/LockPatternUtils.java
+++ b/core/java/com/android/internal/widget/LockPatternUtils.java
@@ -172,6 +172,14 @@
         }
     }
 
+    public void userPresent(int userId) {
+        try {
+            getLockSettings().userPresent(userId);
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
     public static final class RequestThrottledException extends Exception {
         private int mTimeoutMs;
         public RequestThrottledException(int timeoutMs) {
diff --git a/core/java/com/android/internal/widget/ResolverDrawerLayout.java b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
index c4347f8..8b9d503 100644
--- a/core/java/com/android/internal/widget/ResolverDrawerLayout.java
+++ b/core/java/com/android/internal/widget/ResolverDrawerLayout.java
@@ -17,9 +17,15 @@
 
 package com.android.internal.widget;
 
+import com.android.internal.R;
+
 import android.content.Context;
 import android.content.res.TypedArray;
+import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Rect;
+import android.graphics.drawable.ColorDrawable;
+import android.graphics.drawable.Drawable;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -38,7 +44,6 @@
 import android.view.animation.AnimationUtils;
 import android.widget.AbsListView;
 import android.widget.OverScroller;
-import com.android.internal.R;
 
 public class ResolverDrawerLayout extends ViewGroup {
     private static final String TAG = "ResolverDrawerLayout";
@@ -86,6 +91,8 @@
     private final OverScroller mScroller;
     private final VelocityTracker mVelocityTracker;
 
+    private Drawable mScrollIndicatorDrawable;
+
     private OnDismissedListener mOnDismissedListener;
     private RunOnDismissedListener mRunOnDismissedListener;
 
@@ -127,6 +134,8 @@
                 mMaxCollapsedHeight);
         a.recycle();
 
+        mScrollIndicatorDrawable = mContext.getDrawable(R.drawable.scroll_indicator_material);
+
         mScroller = new OverScroller(context, AnimationUtils.loadInterpolator(context,
                 android.R.interpolator.decelerate_quint));
         mVelocityTracker = VelocityTracker.obtain();
@@ -202,8 +211,7 @@
             }
             final boolean isCollapsedNew = mCollapseOffset != 0;
             if (isCollapsedOld != isCollapsedNew) {
-                notifyViewAccessibilityStateChangedIfNeeded(
-                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                onCollapsedChanged(isCollapsedNew);
             }
         } else {
             // Start out collapsed at first unless we restored state for otherwise
@@ -442,8 +450,7 @@
             mTopOffset += dy;
             final boolean isCollapsedNew = newPos != 0;
             if (isCollapsedOld != isCollapsedNew) {
-                notifyViewAccessibilityStateChangedIfNeeded(
-                        AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+                onCollapsedChanged(isCollapsedNew);
             }
             postInvalidateOnAnimation();
             return dy;
@@ -451,6 +458,15 @@
         return 0;
     }
 
+    private void onCollapsedChanged(boolean isCollapsed) {
+        notifyViewAccessibilityStateChangedIfNeeded(
+                AccessibilityEvent.CONTENT_CHANGE_TYPE_UNDEFINED);
+
+        if (mScrollIndicatorDrawable != null) {
+            setWillNotDraw(!isCollapsed);
+        }
+    }
+
     void dispatchOnDismissed() {
         if (mOnDismissedListener != null) {
             mOnDismissedListener.onDismissed();
@@ -709,6 +725,15 @@
     }
 
     @Override
+    public void onDrawForeground(Canvas canvas) {
+        if (mScrollIndicatorDrawable != null) {
+            mScrollIndicatorDrawable.draw(canvas);
+        }
+
+        super.onDrawForeground(canvas);
+    }
+
+    @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int sourceWidth = MeasureSpec.getSize(widthMeasureSpec);
         int widthSize = sourceWidth;
@@ -794,6 +819,8 @@
     protected void onLayout(boolean changed, int l, int t, int r, int b) {
         final int width = getWidth();
 
+        View indicatorHost = null;
+
         int ypos = mTopOffset;
         int leftEdge = getPaddingLeft();
         int rightEdge = width - getPaddingRight();
@@ -802,6 +829,9 @@
         for (int i = 0; i < childCount; i++) {
             final View child = getChildAt(i);
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (lp.hasNestedScrollIndicator) {
+                indicatorHost = child;
+            }
 
             if (child.getVisibility() == GONE) {
                 continue;
@@ -822,6 +852,20 @@
 
             ypos = bottom + lp.bottomMargin;
         }
+
+        if (mScrollIndicatorDrawable != null) {
+            if (indicatorHost != null) {
+                final int left = indicatorHost.getLeft();
+                final int right = indicatorHost.getRight();
+                final int bottom = indicatorHost.getTop();
+                final int top = bottom - mScrollIndicatorDrawable.getIntrinsicHeight();
+                mScrollIndicatorDrawable.setBounds(left, top, right, bottom);
+                setWillNotDraw(!isCollapsed());
+            } else {
+                mScrollIndicatorDrawable = null;
+                setWillNotDraw(true);
+            }
+        }
     }
 
     @Override
@@ -861,6 +905,7 @@
     public static class LayoutParams extends MarginLayoutParams {
         public boolean alwaysShow;
         public boolean ignoreOffset;
+        public boolean hasNestedScrollIndicator;
 
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
@@ -873,6 +918,9 @@
             ignoreOffset = a.getBoolean(
                     R.styleable.ResolverDrawerLayout_LayoutParams_layout_ignoreOffset,
                     false);
+            hasNestedScrollIndicator = a.getBoolean(
+                    R.styleable.ResolverDrawerLayout_LayoutParams_layout_hasNestedScrollIndicator,
+                    false);
             a.recycle();
         }
 
@@ -884,6 +932,7 @@
             super(source);
             this.alwaysShow = source.alwaysShow;
             this.ignoreOffset = source.ignoreOffset;
+            this.hasNestedScrollIndicator = source.hasNestedScrollIndicator;
         }
 
         public LayoutParams(MarginLayoutParams source) {
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 7ff38fd5..d3dca5d9 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -592,6 +592,7 @@
     char jitinitialsizeOptsBuf[sizeof("-Xjitinitialsize:")-1 + PROPERTY_VALUE_MAX];
     char jitthresholdOptsBuf[sizeof("-Xjitthreshold:")-1 + PROPERTY_VALUE_MAX];
     char useJitProfilesOptsBuf[sizeof("-Xjitsaveprofilinginfo:")-1 + PROPERTY_VALUE_MAX];
+    char jitprithreadweightOptBuf[sizeof("-Xjitprithreadweight:")-1 + PROPERTY_VALUE_MAX];
     char gctypeOptsBuf[sizeof("-Xgc:")-1 + PROPERTY_VALUE_MAX];
     char backgroundgcOptsBuf[sizeof("-XX:BackgroundGC=")-1 + PROPERTY_VALUE_MAX];
     char heaptargetutilizationOptsBuf[sizeof("-XX:HeapTargetUtilization=")-1 + PROPERTY_VALUE_MAX];
@@ -701,6 +702,9 @@
     if (strcmp(useJitProfilesOptsBuf, "true") == 0) {
         addOption("-Xjitsaveprofilinginfo");
     }
+    parseRuntimeOption("dalvik.vm.jitprithreadweight",
+                       jitprithreadweightOptBuf,
+                       "-Xjitprithreadweight:");
 
     property_get("ro.config.low_ram", propBuf, "");
     if (strcmp(propBuf, "true") == 0) {
diff --git a/core/jni/android/graphics/SurfaceTexture.cpp b/core/jni/android/graphics/SurfaceTexture.cpp
index 6e9830e..dc9b656 100644
--- a/core/jni/android/graphics/SurfaceTexture.cpp
+++ b/core/jni/android/graphics/SurfaceTexture.cpp
@@ -36,7 +36,7 @@
 
 // ----------------------------------------------------------------------------
 
-#define EGL_QCOM_PROTECTED_CONTENT 0x32E0
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
 
 namespace android {
 
@@ -64,19 +64,12 @@
     EGLDisplay dpy = eglGetCurrentDisplay();
     EGLContext ctx = eglGetCurrentContext();
 
-    if (dpy == EGL_NO_DISPLAY) {
-        ALOGI("isProtectedSurface: invalid current EGLDisplay");
-        return false;
-    }
-
-    if (ctx == EGL_NO_CONTEXT) {
-        ALOGI("isProtectedSurface: invalid current EGLContext");
+    if (dpy == EGL_NO_DISPLAY || ctx == EGL_NO_CONTEXT) {
         return false;
     }
 
     EGLint isProtected = EGL_FALSE;
-    // TODO: Change the enum value below when an extension is ratified.
-    eglQueryContext(dpy, ctx, EGL_QCOM_PROTECTED_CONTENT, &isProtected);
+    eglQueryContext(dpy, ctx, EGL_PROTECTED_CONTENT_EXT, &isProtected);
 
     return isProtected;
 }
diff --git a/core/jni/android_graphics_drawable_VectorDrawable.cpp b/core/jni/android_graphics_drawable_VectorDrawable.cpp
index 50d86ff..0de6549 100644
--- a/core/jni/android_graphics_drawable_VectorDrawable.cpp
+++ b/core/jni/android_graphics_drawable_VectorDrawable.cpp
@@ -175,7 +175,7 @@
 
     PathParser::ParseResult result;
     PathData data;
-    PathParser::getPathDataFromString(&data, &result, pathString, stringLength);
+    PathParser::getPathDataFromAsciiString(&data, &result, pathString, stringLength);
     if (result.failureOccurred) {
         doThrowIAE(env, result.failureMessage.c_str());
     }
diff --git a/core/jni/android_util_PathParser.cpp b/core/jni/android_util_PathParser.cpp
index 0c867f1..53669a8 100644
--- a/core/jni/android_util_PathParser.cpp
+++ b/core/jni/android_util_PathParser.cpp
@@ -34,7 +34,7 @@
     SkPath* skPath = reinterpret_cast<SkPath*>(skPathHandle);
 
     PathParser::ParseResult result;
-    PathParser::parseStringForSkPath(skPath, &result, pathString, strLength);
+    PathParser::parseAsciiStringForSkPath(skPath, &result, pathString, strLength);
     env->ReleaseStringUTFChars(inputPathStr, pathString);
     if (result.failureOccurred) {
         doThrowIAE(env, result.failureMessage.c_str());
@@ -56,7 +56,7 @@
     const char* pathString = env->GetStringUTFChars(inputStr, NULL);
     PathData* pathData = new PathData();
     PathParser::ParseResult result;
-    PathParser::getPathDataFromString(pathData, &result, pathString, strLength);
+    PathParser::getPathDataFromAsciiString(pathData, &result, pathString, strLength);
     env->ReleaseStringUTFChars(inputStr, pathString);
     if (!result.failureOccurred) {
         return reinterpret_cast<jlong>(pathData);
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index faa4192..68c818e 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -479,6 +479,12 @@
     return proxy->pauseSurface(surface);
 }
 
+static void android_view_ThreadedRenderer_setStopped(JNIEnv* env, jobject clazz,
+        jlong proxyPtr, jboolean stopped) {
+    RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
+    proxy->setStopped(stopped);
+}
+
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
         jint width, jint height, jfloat lightRadius, jint ambientShadowAlpha, jint spotShadowAlpha) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
@@ -740,6 +746,7 @@
     { "nInitialize", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
+    { "nSetStopped", "(JZ)V", (void*) android_view_ThreadedRenderer_setStopped },
     { "nSetup", "(JIIFII)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetLightCenter", "(JFFF)V", (void*) android_view_ThreadedRenderer_setLightCenter },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 778f797..1ed93cc 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3008,6 +3008,12 @@
     <permission android:name="android.permission.UPDATE_LOCK_TASK_PACKAGES"
         android:protectionLevel="signature|setup" />
 
+    <!-- @SystemApi Allows an application to replace the app name displayed alongside notifications
+         in the N-release and later.
+         @hide  <p>Not for use by third-party applications.</p> -->
+    <permission android:name="android.permission.SUBSTITUTE_NOTIFICATION_APP_NAME"
+                android:protectionLevel="signature|privileged" />
+
     <application android:process="system"
                  android:persistent="true"
                  android:hasCode="false"
diff --git a/core/res/res/layout/resolver_list.xml b/core/res/res/layout/resolver_list.xml
index 5850e50..ae94503 100644
--- a/core/res/res/layout/resolver_list.xml
+++ b/core/res/res/layout/resolver_list.xml
@@ -30,33 +30,37 @@
         android:layout_height="wrap_content"
         android:layout_alwaysShow="true"
         android:elevation="8dp"
-        android:background="@color/white" >
-        <TextView android:id="@+id/profile_button"
-                  android:layout_width="wrap_content"
-                  android:layout_height="48dp"
-                  android:layout_marginEnd="8dp"
-                  android:paddingStart="8dp"
-                  android:paddingEnd="8dp"
-                  android:visibility="gone"
-                  style="?attr/borderlessButtonStyle"
-                  android:textAppearance="?attr/textAppearanceButton"
-                  android:textColor="@color/material_deep_teal_500"
-                  android:gravity="center_vertical"
-                  android:layout_alignParentTop="true"
-                  android:layout_alignParentRight="true"
-                  android:singleLine="true"/>
-        <TextView android:id="@+id/title"
-                  android:layout_width="wrap_content"
-                  android:layout_height="wrap_content"
-                  android:minHeight="56dp"
-                  android:textAppearance="?attr/textAppearanceMedium"
-                  android:gravity="start|center_vertical"
-                  android:paddingStart="?attr/dialogPreferredPadding"
-                  android:paddingEnd="?attr/dialogPreferredPadding"
-                  android:paddingTop="8dp"
-                  android:layout_below="@id/profile_button"
-                  android:layout_alignParentLeft="true"
-                  android:paddingBottom="8dp" />
+        android:background="@color/white">
+
+        <TextView
+            android:id="@+id/profile_button"
+            android:layout_width="wrap_content"
+            android:layout_height="48dp"
+            android:layout_marginEnd="8dp"
+            android:paddingStart="8dp"
+            android:paddingEnd="8dp"
+            android:visibility="gone"
+            style="?attr/borderlessButtonStyle"
+            android:textAppearance="?attr/textAppearanceButton"
+            android:textColor="@color/material_deep_teal_500"
+            android:gravity="center_vertical"
+            android:layout_alignParentTop="true"
+            android:layout_alignParentRight="true"
+            android:singleLine="true" />
+
+        <TextView
+            android:id="@+id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:minHeight="56dp"
+            android:textAppearance="?attr/textAppearanceMedium"
+            android:gravity="start|center_vertical"
+            android:paddingStart="?attr/dialogPreferredPadding"
+            android:paddingEnd="?attr/dialogPreferredPadding"
+            android:paddingTop="8dp"
+            android:layout_below="@id/profile_button"
+            android:layout_alignParentLeft="true"
+            android:paddingBottom="8dp" />
     </RelativeLayout>
 
     <ListView
@@ -68,6 +72,7 @@
         android:background="@color/white"
         android:elevation="8dp"
         android:nestedScrollingEnabled="true"
+        android:scrollIndicators="top|bottom"
         android:divider="@null" />
 
     <TextView android:id="@+id/empty"
@@ -84,11 +89,12 @@
     <LinearLayout
         android:id="@+id/button_bar"
         android:visibility="gone"
-        style="?android:attr/buttonBarStyle"
+        style="?attr/buttonBarStyle"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_ignoreOffset="true"
         android:layout_alwaysShow="true"
+        android:layout_hasNestedScrollIndicator="true"
         android:gravity="end|center_vertical"
         android:orientation="horizontal"
         android:layoutDirection="locale"
@@ -99,26 +105,30 @@
         android:paddingStart="12dp"
         android:paddingEnd="12dp"
         android:elevation="8dp">
-        <Button android:id="@+id/button_once"
-                android:layout_width="wrap_content"
-                android:layout_gravity="start"
-                android:maxLines="2"
-                style="?android:attr/buttonBarNegativeButtonStyle"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                android:layout_height="wrap_content"
-                android:enabled="false"
-                android:text="@string/activity_resolver_use_once"
-                android:onClick="onButtonClick" />
-        <Button android:id="@+id/button_always"
-                android:layout_width="wrap_content"
-                android:layout_gravity="end"
-                android:maxLines="2"
-                android:minHeight="@dimen/alert_dialog_button_bar_height"
-                style="?android:attr/buttonBarPositiveButtonStyle"
-                android:layout_height="wrap_content"
-                android:enabled="false"
-                android:text="@string/activity_resolver_use_always"
-                android:onClick="onButtonClick" />
+
+        <Button
+            android:id="@+id/button_once"
+            android:layout_width="wrap_content"
+            android:layout_gravity="start"
+            android:maxLines="2"
+            style="?attr/buttonBarNegativeButtonStyle"
+            android:minHeight="@dimen/alert_dialog_button_bar_height"
+            android:layout_height="wrap_content"
+            android:enabled="false"
+            android:text="@string/activity_resolver_use_once"
+            android:onClick="onButtonClick" />
+
+        <Button
+            android:id="@+id/button_always"
+            android:layout_width="wrap_content"
+            android:layout_gravity="end"
+            android:maxLines="2"
+            android:minHeight="@dimen/alert_dialog_button_bar_height"
+            style="?attr/buttonBarPositiveButtonStyle"
+            android:layout_height="wrap_content"
+            android:enabled="false"
+            android:text="@string/activity_resolver_use_always"
+            android:onClick="onButtonClick" />
     </LinearLayout>
 
 </com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/layout/resolver_list_with_default.xml b/core/res/res/layout/resolver_list_with_default.xml
index 31361e5..02dc2ed 100644
--- a/core/res/res/layout/resolver_list_with_default.xml
+++ b/core/res/res/layout/resolver_list_with_default.xml
@@ -22,8 +22,7 @@
     android:layout_height="match_parent"
     android:maxWidth="@dimen/resolver_max_width"
     android:maxCollapsedHeight="144dp"
-    android:id="@id/contentPanel"
-    >
+    android:id="@id/contentPanel">
 
     <LinearLayout
         android:layout_width="match_parent"
@@ -31,66 +30,75 @@
         android:layout_alwaysShow="true"
         android:orientation="vertical"
         android:background="@color/white"
-        android:elevation="8dp" >
+        android:elevation="8dp">
 
         <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="64dp"
-            android:orientation="horizontal" >
+            android:orientation="horizontal">
 
-            <ImageView android:id="@+id/icon"
-                       android:layout_width="24dp"
-                       android:layout_height="24dp"
-                       android:layout_gravity="start|top"
-                       android:layout_marginStart="16dp"
-                       android:layout_marginEnd="16dp"
-                       android:layout_marginTop="20dp"
-                       android:scaleType="fitCenter" />
-            <TextView android:id="@+id/title"
-                      android:layout_width="0dp"
-                      android:layout_weight="1"
-                      android:layout_height="?android:attr/listPreferredItemHeight"
-                      android:layout_marginStart="16dp"
-                      android:textAppearance="?android:attr/textAppearanceMedium"
-                      android:gravity="start|center_vertical"
-                      android:paddingEnd="16dp" />
-            <LinearLayout android:id="@+id/profile_button"
-                          android:layout_width="wrap_content"
-                          android:layout_height="48dp"
-                          android:layout_marginTop="4dp"
-                          android:layout_marginEnd="4dp"
-                          android:paddingStart="8dp"
-                          android:paddingEnd="8dp"
-                          android:paddingTop="4dp"
-                          android:paddingBottom="4dp"
-                          android:focusable="true"
-                          android:visibility="gone"
-                          style="?attr/borderlessButtonStyle">
-                <ImageView android:id="@+id/icon"
-                           android:layout_width="24dp"
-                           android:layout_height="24dp"
-                           android:layout_gravity="start|center_vertical"
-                           android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
-                           android:layout_marginTop="12dp"
-                           android:layout_marginBottom="12dp"
-                           android:scaleType="fitCenter" />
-                <TextView android:id="@id/text1"
-                          android:layout_width="wrap_content"
-                          android:layout_height="wrap_content"
-                          android:layout_gravity="start|center_vertical"
-                          android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
-                          android:textAppearance="?attr/textAppearanceButton"
-                          android:textColor="?attr/textColorPrimary"
-                          android:minLines="1"
-                          android:maxLines="1"
-                          android:ellipsize="marquee" />
+            <ImageView
+                android:id="@+id/icon"
+                android:layout_width="24dp"
+                android:layout_height="24dp"
+                android:layout_gravity="start|top"
+                android:layout_marginStart="16dp"
+                android:layout_marginEnd="16dp"
+                android:layout_marginTop="20dp"
+                android:scaleType="fitCenter" />
+
+            <TextView
+                android:id="@+id/title"
+                android:layout_width="0dp"
+                android:layout_weight="1"
+                android:layout_height="?attr/listPreferredItemHeight"
+                android:layout_marginStart="16dp"
+                android:textAppearance="?attr/textAppearanceMedium"
+                android:gravity="start|center_vertical"
+                android:paddingEnd="16dp" />
+
+            <LinearLayout
+                android:id="@+id/profile_button"
+                android:layout_width="wrap_content"
+                android:layout_height="48dp"
+                android:layout_marginTop="4dp"
+                android:layout_marginEnd="4dp"
+                android:paddingStart="8dp"
+                android:paddingEnd="8dp"
+                android:paddingTop="4dp"
+                android:paddingBottom="4dp"
+                android:focusable="true"
+                android:visibility="gone"
+                style="?attr/borderlessButtonStyle">
+
+                <ImageView
+                    android:id="@+id/icon"
+                    android:layout_width="24dp"
+                    android:layout_height="24dp"
+                    android:layout_gravity="start|center_vertical"
+                    android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+                    android:layout_marginTop="12dp"
+                    android:layout_marginBottom="12dp"
+                    android:scaleType="fitCenter" />
+
+                <TextView
+                    android:id="@id/text1"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="start|center_vertical"
+                    android:layout_marginEnd="?attr/listPreferredItemPaddingEnd"
+                    android:textAppearance="?attr/textAppearanceButton"
+                    android:textColor="?attr/textColorPrimary"
+                    android:minLines="1"
+                    android:maxLines="1"
+                    android:ellipsize="marquee" />
             </LinearLayout>
         </LinearLayout>
 
         <LinearLayout
             android:id="@+id/button_bar"
             android:visibility="gone"
-            style="?android:attr/buttonBarStyle"
+            style="?attr/buttonBarStyle"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_alwaysShow="true"
@@ -104,30 +112,36 @@
             android:paddingEnd="12dp"
             android:background="@color/white"
             android:elevation="8dp">
-            <Button android:id="@+id/button_once"
-                    android:layout_width="wrap_content"
-                    android:layout_gravity="start"
-                    android:maxLines="2"
-                    style="?android:attr/buttonBarNegativeButtonStyle"
-                    android:minHeight="@dimen/alert_dialog_button_bar_height"
-                    android:layout_height="wrap_content"
-                    android:enabled="false"
-                    android:text="@string/activity_resolver_use_once"
-                    android:onClick="onButtonClick" />
-            <Button android:id="@+id/button_always"
-                    android:layout_width="wrap_content"
-                    android:layout_gravity="end"
-                    android:maxLines="2"
-                    android:minHeight="@dimen/alert_dialog_button_bar_height"
-                    style="?android:attr/buttonBarPositiveButtonStyle"
-                    android:layout_height="wrap_content"
-                    android:enabled="false"
-                    android:text="@string/activity_resolver_use_always"
-                    android:onClick="onButtonClick" />
+
+            <Button
+                android:id="@+id/button_once"
+                android:layout_width="wrap_content"
+                android:layout_gravity="start"
+                android:maxLines="2"
+                style="?attr/buttonBarNegativeButtonStyle"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                android:layout_height="wrap_content"
+                android:enabled="false"
+                android:text="@string/activity_resolver_use_once"
+                android:onClick="onButtonClick" />
+
+            <Button
+                android:id="@+id/button_always"
+                android:layout_width="wrap_content"
+                android:layout_gravity="end"
+                android:maxLines="2"
+                android:minHeight="@dimen/alert_dialog_button_bar_height"
+                style="?attr/buttonBarPositiveButtonStyle"
+                android:layout_height="wrap_content"
+                android:enabled="false"
+                android:text="@string/activity_resolver_use_always"
+                android:onClick="onButtonClick" />
         </LinearLayout>
-        <View android:layout_width="match_parent"
-              android:layout_height="1dp"
-              android:background="?android:attr/dividerVertical" />
+
+        <View
+            android:layout_width="match_parent"
+            android:layout_height="1dp"
+            android:background="?attr/dividerVertical" />
     </LinearLayout>
 
     <ListView
@@ -139,7 +153,6 @@
         android:background="@color/white"
         android:elevation="8dp"
         android:nestedScrollingEnabled="true"
-        android:divider="@null"
-        />
+        android:divider="@null" />
 
 </com.android.internal.widget.ResolverDrawerLayout>
diff --git a/core/res/res/values-mcc310-mnc160/strings.xml b/core/res/res/values-mcc310-mnc160/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc160/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc200/strings.xml b/core/res/res/values-mcc310-mnc200/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc200/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc210/strings.xml b/core/res/res/values-mcc310-mnc210/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc210/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc220/strings.xml b/core/res/res/values-mcc310-mnc220/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc220/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc230/strings.xml b/core/res/res/values-mcc310-mnc230/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc230/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc240/strings.xml b/core/res/res/values-mcc310-mnc240/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc240/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc250/strings.xml b/core/res/res/values-mcc310-mnc250/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc250/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc260/strings.xml b/core/res/res/values-mcc310-mnc260/strings.xml
deleted file mode 100644
index dc79877..0000000
--- a/core/res/res/values-mcc310-mnc260/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** Copyright 2015, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License");
-** you may not use this file except in compliance with the License.
-** You my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc270/strings.xml b/core/res/res/values-mcc310-mnc270/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc270/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc310/strings.xml b/core/res/res/values-mcc310-mnc310/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc310/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc490/strings.xml b/core/res/res/values-mcc310-mnc490/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc490/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc660/strings.xml b/core/res/res/values-mcc310-mnc660/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc660/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values-mcc310-mnc800/strings.xml b/core/res/res/values-mcc310-mnc800/strings.xml
deleted file mode 100644
index 526d08b..0000000
--- a/core/res/res/values-mcc310-mnc800/strings.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-/*
-** 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 my 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.
-*/
--->
-
-<!-- These resources are around just to allow their values to be customized
-     for different hardware and product builds. -->
-<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false">
-        <item>REG09</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages">
-        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
-    </string-array>
-    <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages">
-        <item>Register with your carrier</item>
-    </string-array>
-    <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s Wi-Fi Calling</string>
-</resources>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index a320ef6..85e0b88 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -8138,6 +8138,7 @@
         <attr name="layout_alwaysShow" format="boolean" />
         <attr name="layout_ignoreOffset" format="boolean" />
         <attr name="layout_gravity" />
+        <attr name="layout_hasNestedScrollIndicator" format="boolean" />
     </declare-styleable>
 
     <!-- @hide -->
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 6ff7139..80b3a64 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2713,11 +2713,14 @@
     <public type="attr" name="forceHasOverlappingRendering" />
     <public type="attr" name="contentInsetStartWithNavigation" />
     <public type="attr" name="contentInsetEndWithActions" />
+    <public type="attr" name="numberPickerStyle" />
 
     <public type="style" name="Theme.Material.Light.DialogWhenLarge.DarkActionBar" />
     <public type="style" name="Widget.Material.SeekBar.Discrete" />
     <public type="style" name="Widget.Material.CompoundButton.Switch" />
     <public type="style" name="Widget.Material.Light.CompoundButton.Switch" />
+    <public type="style" name="Widget.Material.NumberPicker" />
+    <public type="style" name="Widget.Material.Light.NumberPicker" />
 
     <public type="id" name="accessibilityActionSetProgress" />
     <public type="id" name="icon_frame" />
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index fa799c9..836efde 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -245,16 +245,19 @@
 
     <!-- Displayed when WFC registration fails -->
     <string name="wfcRegErrorTitle">Wi-Fi Calling</string>
-    <!-- WFC Operator Error Codes -->
-    <string-array name="wfcOperatorErrorCodes" translatable="false" />
     <!-- WFC Operator Error Messages showed as alerts -->
-    <string-array name="wfcOperatorErrorAlertMessages" />
+    <string-array name="wfcOperatorErrorAlertMessages">
+        <item>To make calls and send messages over Wi-Fi, first ask your carrier to set up this service. Then turn on Wi-Fi calling again from Settings.</item>
+    </string-array>
     <!-- WFC Operator Error Messages showed as notifications -->
-    <string-array name="wfcOperatorErrorNotificationMessages" />
+    <string-array name="wfcOperatorErrorNotificationMessages">
+        <item>Register with your carrier</item>
+    </string-array>
     <!-- Template for showing cellular network operator name while WFC is active -->
-    <string name="wfcSpnFormat">%s</string>
-    <!-- Template for showing operator name for data connection while WFC is active -->
-    <string name="wfcDataSpnFormat">%s</string>
+    <string-array name="wfcSpnFormats">
+        <item>%s</item>
+        <item>%s Wi-Fi Calling</item>
+    </string-array>
     <!-- WFC, summary for Disabled -->
     <string name="wifi_calling_off_summary">Off</string>
     <!-- WFC, summary for Wi-Fi Preferred -->
@@ -4048,6 +4051,9 @@
     <!-- [CHAR_LIMIT=NONE] Battery saver: Feature description -->
     <string name="battery_saver_description">To help improve battery life, battery saver reduces your device’s performance and limits vibration, location services, and most background data. Email, messaging, and other apps that rely on syncing may not update unless you open them.\n\nBattery saver turns off automatically when your device is charging.</string>
 
+    <!-- [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>
+
     <!-- Zen mode condition - summary: time duration in minutes. [CHAR LIMIT=NONE] -->
     <plurals name="zen_mode_duration_minutes_summary">
         <item quantity="one">For one minute (until <xliff:g id="formattedTime" example="10:00 PM">%2$s</xliff:g>)</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e37f8d5..a35b409 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -771,11 +771,9 @@
   <java-symbol type="string" name="phoneTypeWorkMobile" />
   <java-symbol type="string" name="phoneTypeWorkPager" />
   <java-symbol type="string" name="wfcRegErrorTitle" />
-  <java-symbol type="array" name="wfcOperatorErrorCodes" />
   <java-symbol type="array" name="wfcOperatorErrorAlertMessages" />
   <java-symbol type="array" name="wfcOperatorErrorNotificationMessages" />
-  <java-symbol type="string" name="wfcSpnFormat" />
-  <java-symbol type="string" name="wfcDataSpnFormat" />
+  <java-symbol type="array" name="wfcSpnFormats" />
   <java-symbol type="string" name="wifi_calling_off_summary" />
   <java-symbol type="string" name="wfc_mode_wifi_preferred_summary" />
   <java-symbol type="string" name="wfc_mode_cellular_preferred_summary" />
@@ -2102,6 +2100,7 @@
   <java-symbol type="dimen" name="timepicker_text_size_normal" />
   <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="zen_mode_forever" />
   <java-symbol type="string" name="zen_mode_forever_dnd" />
   <java-symbol type="string" name="zen_mode_rule_name_combination" />
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index bcac6a1..117e17b 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -320,6 +320,7 @@
     </family>
     <family lang="und-Tibt">
         <font weight="400" style="normal">NotoSansTibetan-Regular.ttf</font>
+        <font weight="700" style="normal">NotoSansTibetan-Bold.ttf</font>
     </family>
     <family lang="und-Tfng">
         <font weight="400" style="normal">NotoSansTifinagh-Regular.ttf</font>
@@ -350,6 +351,9 @@
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
     </family>
     <family>
+        <font weight="400" style="normal">NotoSansSymbols-Regular-Subsetted2.ttf</font>
+    </family>
+    <family>
         <font weight="400" style="normal">DroidSansFallback.ttf</font>
     </family>
     <!--
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index aa1ed0a..026f7a0 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -152,8 +152,10 @@
 
 <p>Generating a new {@link java.security.PrivateKey} requires that
   you also specify the initial X.509 attributes that the self-signed
-  certificate will have. You can replace the certificate at a later
-  time with a certificate signed by a Certificate Authority.</p>
+  certificate will have. You can use
+  {@link java.security.KeyStore#setKeyEntry(String, java.security.Key, char[], java.security.cert.Certificate[]) KeyStore.setKeyEntry}
+  to replace the certificate at a later time with a certificate signed
+  by a Certificate Authority (CA).</p>
 
 <p>To generate the key, use a {@link java.security.KeyPairGenerator}
   with {@link android.security.KeyPairGeneratorSpec}:</p>
diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java
index 1d95563..7f3a437 100644
--- a/graphics/java/android/graphics/drawable/Drawable.java
+++ b/graphics/java/android/graphics/drawable/Drawable.java
@@ -121,6 +121,47 @@
  *     whose overall size is modified based on the current level.
  * </ul>
  *
+ * <a name="Custom"></a>
+ * <h3>Custom drawables</h3>
+ *
+ * <p>
+ * All versions of Android allow the Drawable class to be extended and used at
+ * run time in place of framework-provided drawable classes. Starting in
+ * {@link android.os.Build.VERSION_CODES#N API 24}, custom drawables classes
+ * may also be used in XML.
+ * <p>
+ * <strong>Note:</strong> Custom drawable classes are only accessible from
+ * within your application package. Other applications will not be able to load
+ * them.
+ * <p>
+ * At a minimum, custom drawable classes must implement the abstract methods on
+ * Drawable and should override the {@link Drawable#draw(Canvas)} method to
+ * draw content.
+ * <p>
+ * Custom drawables classes may be used in XML in multiple ways:
+ * <ul>
+ *     <li>
+ *         Using the fully-qualified class name as the XML element name. For
+ *         this method, the custom drawable class must be a public top-level
+ *         class.
+ * <pre>
+ * &lt;com.myapp.MyCustomDrawable xmlns:android="http://schemas.android.com/apk/res/android"
+ *     android:color="#ffff0000" /&gt;
+ * </pre>
+ *     </li>
+ *     <li>
+ *         Using <em>drawable</em> as the XML element name and specifying the
+ *         fully-qualified class name from the <em>class</em> attribute. This
+ *         method may be used for both public top-level classes and public
+ *         static inner classes.
+ * <pre>
+ * &lt;drawable xmlns:android="http://schemas.android.com/apk/res/android"
+ *     class="com.myapp.MyTopLevelClass$InnerCustomDrawable"
+ *     android:color="#ffff0000" /&gt;
+ * </pre>
+ *     </li>
+ * </ul>
+ *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For more information about how to use drawables, read the
@@ -444,6 +485,9 @@
      * @param layoutDirection the resolved layout direction for the drawable,
      *                        either {@link android.view.View#LAYOUT_DIRECTION_LTR}
      *                        or {@link android.view.View#LAYOUT_DIRECTION_RTL}
+     * @return {@code true} if the layout direction change has caused the
+     *         appearance of the drawable to change such that it needs to be
+     *         re-drawn, {@code false} otherwise
      * @see #getLayoutDirection()
      */
     public final boolean setLayoutDirection(@View.ResolvedLayoutDir int layoutDirection) {
@@ -458,8 +502,9 @@
      * Called when the drawable's resolved layout direction changes.
      *
      * @param layoutDirection the new resolved layout direction
-     * @return true if the layout direction change has caused the appearance of
-     *         the drawable to change and it needs to be re-drawn
+     * @return {@code true} if the layout direction change has caused the
+     *         appearance of the drawable to change such that it needs to be
+     *         re-drawn, {@code false} otherwise
      * @see #setLayoutDirection(int)
      */
     public boolean onLayoutDirectionChanged(@View.ResolvedLayoutDir int layoutDirection) {
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 6913f43..715c875 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -34,9 +34,7 @@
 #include <utils/String8.h>
 #include <utils/threads.h>
 #include <utils/Timers.h>
-#ifdef __ANDROID__
-#include <cutils/trace.h>
-#endif
+#include <utils/Trace.h>
 
 #include <assert.h>
 #include <dirent.h>
@@ -54,14 +52,6 @@
     _rc; })
 #endif
 
-#ifdef __ANDROID__
-#define MY_TRACE_BEGIN(x) ATRACE_BEGIN(x)
-#define MY_TRACE_END() ATRACE_END()
-#else
-#define MY_TRACE_BEGIN(x)
-#define MY_TRACE_END()
-#endif
-
 using namespace android;
 
 static const bool kIsDebug = false;
@@ -623,7 +613,7 @@
     ResTable* sharedRes = NULL;
     bool shared = true;
     bool onlyEmptyResources = true;
-    MY_TRACE_BEGIN(ap.path.string());
+    ATRACE_NAME(ap.path.string());
     Asset* idmap = openIdmapLocked(ap);
     size_t nextEntryIdx = mResources->getTableCount();
     ALOGV("Looking for resource asset in '%s'\n", ap.path.string());
@@ -703,8 +693,6 @@
     if (idmap != NULL) {
         delete idmap;
     }
-    MY_TRACE_END();
-
     return onlyEmptyResources;
 }
 
@@ -752,6 +740,7 @@
 
 void AssetManager::updateResourceParamsLocked() const
 {
+    ATRACE_CALL();
     ResTable* res = mResources;
     if (!res) {
         return;
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 1ccc59a..15cb684 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -24,6 +24,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include <algorithm>
 #include <limits>
 #include <memory>
 #include <type_traits>
@@ -5810,6 +5811,10 @@
     return NULL;
 }
 
+static bool compareResTableConfig(const ResTable_config& a, const ResTable_config& b) {
+    return a.compare(b) < 0;
+}
+
 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
         bool ignoreAndroidPackage, bool includeSystemConfigs) const {
     const size_t packageCount = mPackageGroups.size();
@@ -5840,17 +5845,11 @@
                     ResTable_config cfg;
                     memset(&cfg, 0, sizeof(ResTable_config));
                     cfg.copyFromDtoH(config->config);
-                    // only insert unique
-                    const size_t N = configs->size();
-                    size_t n;
-                    for (n = 0; n < N; n++) {
-                        if (0 == (*configs)[n].compare(cfg)) {
-                            break;
-                        }
-                    }
-                    // if we didn't find it
-                    if (n == N) {
-                        configs->add(cfg);
+
+                    auto iter = std::lower_bound(configs->begin(), configs->end(), cfg,
+                                                 compareResTableConfig);
+                    if (iter == configs->end() || iter->compare(cfg) != 0) {
+                        configs->insertAt(cfg, std::distance(configs->begin(), iter));
                     }
                 }
             }
@@ -5858,6 +5857,10 @@
     }
 }
 
+static bool compareString8AndCString(const String8& str, const char* cStr) {
+    return strcmp(str.string(), cStr) < 0;
+}
+
 void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     Vector<ResTable_config> configs;
@@ -5872,15 +5875,11 @@
     char locale[RESTABLE_MAX_LOCALE_LEN];
     for (size_t i=0; i<I; i++) {
         configs[i].getBcp47Locale(locale);
-        const size_t J = locales->size();
-        size_t j;
-        for (j=0; j<J; j++) {
-            if (0 == strcmp(locale, (*locales)[j].string())) {
-                break;
-            }
-        }
-        if (j == J) {
-            locales->add(String8(locale));
+
+        auto iter = std::lower_bound(locales->begin(), locales->end(), locale,
+                                     compareString8AndCString);
+        if (iter == locales->end() || strcmp(iter->string(), locale) != 0) {
+            locales->insertAt(String8(locale), std::distance(locales->begin(), iter));
         }
     }
 }
diff --git a/libs/androidfw/tests/ResTable_test.cpp b/libs/androidfw/tests/ResTable_test.cpp
index 7cd7fb5..b8b4625 100644
--- a/libs/androidfw/tests/ResTable_test.cpp
+++ b/libs/androidfw/tests/ResTable_test.cpp
@@ -39,8 +39,20 @@
  */
 #include "data/basic/basic_arsc.h"
 
+/**
+ * Include a binary library resource table.
+ *
+ * Package: com.android.test.basic
+ */
 #include "data/lib/lib_arsc.h"
 
+/**
+ * Include a system resource table.
+ *
+ * Package: android
+ */
+#include "data/system/system_arsc.h"
+
 TEST(ResTableTest, shouldLoadSuccessfully) {
     ResTable table;
     ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
@@ -324,4 +336,25 @@
     ASSERT_EQ(uint32_t(600), val.data);
 }
 
+TEST(ResTableTest, GetConfigurationsReturnsUniqueList) {
+    ResTable table;
+    ASSERT_EQ(NO_ERROR, table.add(system_arsc, system_arsc_len));
+    ASSERT_EQ(NO_ERROR, table.add(basic_arsc, basic_arsc_len));
+
+    ResTable_config configSv;
+    memset(&configSv, 0, sizeof(configSv));
+    configSv.language[0] = 's';
+    configSv.language[1] = 'v';
+
+    Vector<ResTable_config> configs;
+    table.getConfigurations(&configs);
+
+    EXPECT_EQ(1, std::count(configs.begin(), configs.end(), configSv));
+
+    Vector<String8> locales;
+    table.getLocales(&locales);
+
+    EXPECT_EQ(1, std::count(locales.begin(), locales.end(), String8("sv")));
+}
+
 } // namespace
diff --git a/libs/androidfw/tests/TestHelpers.h b/libs/androidfw/tests/TestHelpers.h
index ac80d88..ff9be16 100644
--- a/libs/androidfw/tests/TestHelpers.h
+++ b/libs/androidfw/tests/TestHelpers.h
@@ -21,7 +21,7 @@
 enum { MAY_NOT_BE_BAG = false };
 
 static inline bool operator==(const android::ResTable_config& a, const android::ResTable_config& b) {
-    return memcmp(&a, &b, sizeof(a)) == 0;
+    return a.compare(b) == 0;
 }
 
 static inline ::std::ostream& operator<<(::std::ostream& out, const android::ResTable_config& c) {
diff --git a/libs/androidfw/tests/data/system/R.h b/libs/androidfw/tests/data/system/R.h
index 27f25fe..6a31fb8 100644
--- a/libs/androidfw/tests/data/system/R.h
+++ b/libs/androidfw/tests/data/system/R.h
@@ -33,6 +33,12 @@
     };
 }
 
+namespace integer {
+    enum {
+        number = 0x01030000, // sv
+    };
+}
+
 } // namespace R
 } // namespace android
 
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/libs/androidfw/tests/data/system/res/values-sv/values.xml
similarity index 70%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to libs/androidfw/tests/data/system/res/values-sv/values.xml
index 681ff91..b97bdb6 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/libs/androidfw/tests/data/system/res/values-sv/values.xml
@@ -14,8 +14,7 @@
      limitations under the License.
 -->
 
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:propertyName="alpha"
-    android:valueTo="1"
-    android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+<resources>
+    <public type="integer" name="number" id="0x01030000" />
+    <integer name="number">1</integer>
+</resources>
diff --git a/libs/androidfw/tests/data/system/system_arsc.h b/libs/androidfw/tests/data/system/system_arsc.h
index 215ecae..b0dab6b 100644
--- a/libs/androidfw/tests/data/system/system_arsc.h
+++ b/libs/androidfw/tests/data/system/system_arsc.h
@@ -1,8 +1,8 @@
 unsigned char system_arsc[] = {
-  0x02, 0x00, 0x0c, 0x00, 0x18, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x02, 0x00, 0x0c, 0x00, 0xf8, 0x03, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x01, 0x00, 0x1c, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xf0, 0x02, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x20, 0x01, 0xd0, 0x03, 0x00, 0x00,
   0x01, 0x00, 0x00, 0x00, 0x61, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x72, 0x00,
   0x6f, 0x00, 0x69, 0x00, 0x64, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -25,26 +25,33 @@
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x01, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x60, 0x01, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x40, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x0c, 0x00, 0x00, 0x00, 0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00,
-  0x72, 0x00, 0x00, 0x00, 0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00,
-  0x6c, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00,
-  0x70, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x98, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x78, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x0c, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x00, 0x00,
+  0x05, 0x00, 0x73, 0x00, 0x74, 0x00, 0x79, 0x00, 0x6c, 0x00, 0x65, 0x00,
+  0x00, 0x00, 0x07, 0x00, 0x69, 0x00, 0x6e, 0x00, 0x74, 0x00, 0x65, 0x00,
+  0x67, 0x00, 0x65, 0x00, 0x72, 0x00, 0x00, 0x00, 0x0d, 0x00, 0x5e, 0x00,
+  0x61, 0x00, 0x74, 0x00, 0x74, 0x00, 0x72, 0x00, 0x2d, 0x00, 0x70, 0x00,
+  0x72, 0x00, 0x69, 0x00, 0x76, 0x00, 0x61, 0x00, 0x74, 0x00, 0x65, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x1c, 0x00, 0x84, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x2c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x18, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x46, 0x00, 0x00, 0x00,
   0x0a, 0x00, 0x62, 0x00, 0x61, 0x00, 0x63, 0x00, 0x6b, 0x00, 0x67, 0x00,
   0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
   0x0a, 0x00, 0x66, 0x00, 0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x67, 0x00,
   0x72, 0x00, 0x6f, 0x00, 0x75, 0x00, 0x6e, 0x00, 0x64, 0x00, 0x00, 0x00,
   0x09, 0x00, 0x54, 0x00, 0x68, 0x00, 0x65, 0x00, 0x6d, 0x00, 0x65, 0x00,
-  0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x40,
-  0x01, 0x02, 0x44, 0x00, 0x84, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x4c, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00,
+  0x2e, 0x00, 0x4f, 0x00, 0x6e, 0x00, 0x65, 0x00, 0x00, 0x00, 0x06, 0x00,
+  0x6e, 0x00, 0x75, 0x00, 0x6d, 0x00, 0x62, 0x00, 0x65, 0x00, 0x72, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x18, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40,
+  0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x8c, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x54, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -55,15 +62,27 @@
   0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x01, 0x08, 0x00, 0x00, 0x10, 0x11, 0x00, 0x00, 0x00,
   0x02, 0x02, 0x10, 0x00, 0x14, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x44, 0x00,
-  0x70, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
-  0x48, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00,
+  0x78, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x50, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00,
-  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
-  0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff,
-  0x01, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x03, 0x00, 0x02, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x01,
+  0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0xff, 0xff, 0x01, 0x00, 0x01, 0x01,
+  0x08, 0x00, 0x00, 0x1d, 0x00, 0x00, 0x00, 0xff, 0x02, 0x02, 0x10, 0x00,
+  0x14, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x40, 0x01, 0x02, 0x4c, 0x00, 0x60, 0x00, 0x00, 0x00,
+  0x03, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00,
+  0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x73, 0x76, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x08, 0x00, 0x02, 0x00, 0x03, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x10,
+  0x01, 0x00, 0x00, 0x00, 0x02, 0x02, 0x10, 0x00, 0x10, 0x00, 0x00, 0x00,
+  0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
 };
-unsigned int system_arsc_len = 792;
+unsigned int system_arsc_len = 1016;
diff --git a/libs/hwui/Animator.cpp b/libs/hwui/Animator.cpp
index bd71e0d..4d65782 100644
--- a/libs/hwui/Animator.cpp
+++ b/libs/hwui/Animator.cpp
@@ -226,7 +226,7 @@
         // Set to 0 so that the animate() basically instantly finishes
         mStartTime = 0;
     }
-    if (mDuration < 0 || mDuration > 50000) {
+    if (mDuration < 0) {
         ALOGW("Your duration is strange and confusing: %" PRId64, mDuration);
     }
 }
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 35fe06d..fe68239 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -253,7 +253,9 @@
     path.transform(skTransform, &transformed);
     SkRegion region;
     regionFromPath(transformed, region);
-    clipRegion(region, op);
+    enterRegionMode();
+    mClipRegion.op(region, op);
+    onClipRegionUpdated();
 }
 
 /*
diff --git a/libs/hwui/PathParser.cpp b/libs/hwui/PathParser.cpp
index 7e85333..2179f14 100644
--- a/libs/hwui/PathParser.cpp
+++ b/libs/hwui/PathParser.cpp
@@ -162,7 +162,7 @@
             || verb == 's' || verb == 't' || verb == 'v' || verb == 'z';
 }
 
-void PathParser::getPathDataFromString(PathData* data, ParseResult* result,
+void PathParser::getPathDataFromAsciiString(PathData* data, ParseResult* result,
         const char* pathStr, size_t strLen) {
     if (pathStr == NULL) {
         result->failureOccurred = true;
@@ -171,7 +171,16 @@
     }
 
     size_t start = 0;
-    size_t end = 1;
+    // Skip leading spaces.
+    while (isspace(pathStr[start]) && start < strLen) {
+        start++;
+    }
+    if (start == strLen) {
+        result->failureOccurred = true;
+        result->failureMessage = "Path string cannot be empty.";
+        return;
+    }
+    size_t end = start + 1;
 
     while (end < strLen) {
         end = nextStart(pathStr, strLen, end);
@@ -226,9 +235,9 @@
     ALOGD("points are : %s", os.str().c_str());
 }
 
-void PathParser::parseStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
+void PathParser::parseAsciiStringForSkPath(SkPath* skPath, ParseResult* result, const char* pathStr, size_t strLen) {
     PathData pathData;
-    getPathDataFromString(&pathData, result, pathStr, strLen);
+    getPathDataFromAsciiString(&pathData, result, pathStr, strLen);
     if (result->failureOccurred) {
         return;
     }
diff --git a/libs/hwui/PathParser.h b/libs/hwui/PathParser.h
index 180a7a3..5578e8d 100644
--- a/libs/hwui/PathParser.h
+++ b/libs/hwui/PathParser.h
@@ -39,9 +39,9 @@
     /**
      * Parse the string literal and create a Skia Path. Return true on success.
      */
-    ANDROID_API static void parseStringForSkPath(SkPath* outPath, ParseResult* result,
+    ANDROID_API static void parseAsciiStringForSkPath(SkPath* outPath, ParseResult* result,
             const char* pathStr, size_t strLength);
-    ANDROID_API static void getPathDataFromString(PathData* outData, ParseResult* result,
+    ANDROID_API static void getPathDataFromAsciiString(PathData* outData, ParseResult* result,
             const char* pathStr, size_t strLength);
     static void dump(const PathData& data);
     static bool isVerbValid(char verb);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index adfe45c..ac17ed2 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -96,7 +96,7 @@
 Path::Path(const char* pathStr, size_t strLength) {
     PathParser::ParseResult result;
     Data data;
-    PathParser::getPathDataFromString(&data, &result, pathStr, strLength);
+    PathParser::getPathDataFromAsciiString(&data, &result, pathStr, strLength);
     mStagingProperties.setData(data);
 }
 
diff --git a/libs/hwui/VectorDrawable.h b/libs/hwui/VectorDrawable.h
index e4c7ed7..691cfa0 100644
--- a/libs/hwui/VectorDrawable.h
+++ b/libs/hwui/VectorDrawable.h
@@ -40,11 +40,11 @@
 namespace uirenderer {
 
 namespace VectorDrawable {
-#define VD_SET_PROP_WITH_FLAG(field, value, flag) (VD_SET_PROP_AND_NOTIFY(field, value) ? (flag = true, true) : false)
-#define VD_SET_PROP(field, value) (value != field ? (field = value, true) : false)
-#define VD_SET_PROP_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP(field, value);\
+#define VD_SET_PRIMITIVE_FIELD_WITH_FLAG(field, value, flag) (VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, (value)) ? ((flag) = true, true) : false)
+#define VD_SET_PROP(field, value) ((value) != (field) ? ((field) = (value), true) : false)
+#define VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(field, value) ({ bool retVal = VD_SET_PROP((mPrimitiveFields.field), (value));\
     onPropertyChanged(); retVal;})
-#define UPDATE_SKPROP(field, value) ({bool retVal = (field != value); if (field != value) SkRefCnt_SafeAssign(field, value); retVal;})
+#define UPDATE_SKPROP(field, value) ({bool retVal = ((field) != (value)); if ((field) != (value)) SkRefCnt_SafeAssign((field), (value)); retVal;})
 
 /* A VectorDrawable is composed of a tree of nodes.
  * Each node can be a group node, or a path.
@@ -248,49 +248,49 @@
             return mPrimitiveFields.strokeWidth;
         }
         void setStrokeWidth(float strokeWidth) {
-            VD_SET_PROP_AND_NOTIFY(strokeWidth, strokeWidth);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeWidth, strokeWidth);
         }
         SkColor getStrokeColor() const{
             return mPrimitiveFields.strokeColor;
         }
         void setStrokeColor(SkColor strokeColor) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeColor, strokeColor);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeColor, strokeColor);
         }
         float getStrokeAlpha() const{
             return mPrimitiveFields.strokeAlpha;
         }
         void setStrokeAlpha(float strokeAlpha) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.strokeAlpha, strokeAlpha);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(strokeAlpha, strokeAlpha);
         }
         SkColor getFillColor() const {
             return mPrimitiveFields.fillColor;
         }
         void setFillColor(SkColor fillColor) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillColor, fillColor);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillColor, fillColor);
         }
         float getFillAlpha() const{
             return mPrimitiveFields.fillAlpha;
         }
         void setFillAlpha(float fillAlpha) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.fillAlpha, fillAlpha);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(fillAlpha, fillAlpha);
         }
         float getTrimPathStart() const{
             return mPrimitiveFields.trimPathStart;
         }
         void setTrimPathStart(float trimPathStart) {
-            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathStart, trimPathStart, mTrimDirty);
+            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathStart, trimPathStart, mTrimDirty);
         }
         float getTrimPathEnd() const{
             return mPrimitiveFields.trimPathEnd;
         }
         void setTrimPathEnd(float trimPathEnd) {
-            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathEnd, trimPathEnd, mTrimDirty);
+            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathEnd, trimPathEnd, mTrimDirty);
         }
         float getTrimPathOffset() const{
             return mPrimitiveFields.trimPathOffset;
         }
         void setTrimPathOffset(float trimPathOffset) {
-            VD_SET_PROP_WITH_FLAG(mPrimitiveFields.trimPathOffset, trimPathOffset, mTrimDirty);
+            VD_SET_PRIMITIVE_FIELD_WITH_FLAG(trimPathOffset, trimPathOffset, mTrimDirty);
         }
 
         float getStrokeMiterLimit() const {
@@ -425,43 +425,43 @@
             return mPrimitiveFields.rotate;
         }
         void setRotation(float rotation) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.rotate, rotation);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(rotate, rotation);
         }
         float getPivotX() const {
             return mPrimitiveFields.pivotX;
         }
         void setPivotX(float pivotX) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotX, pivotX);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotX, pivotX);
         }
         float getPivotY() const {
             return mPrimitiveFields.pivotY;
         }
         void setPivotY(float pivotY) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.pivotY, pivotY);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(pivotY, pivotY);
         }
         float getScaleX() const {
             return mPrimitiveFields.scaleX;
         }
         void setScaleX(float scaleX) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleX, scaleX);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleX, scaleX);
         }
         float getScaleY() const {
             return mPrimitiveFields.scaleY;
         }
         void setScaleY(float scaleY) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.scaleY, scaleY);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(scaleY, scaleY);
         }
         float getTranslateX() const {
             return mPrimitiveFields.translateX;
         }
         void setTranslateX(float translateX) {
-            VD_SET_PROP_AND_NOTIFY(mPrimitiveFields.translateX, translateX);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateX, translateX);
         }
         float getTranslateY() const {
             return mPrimitiveFields.translateY;
         }
         void setTranslateY(float translateY) {
-            VD_SET_PROP_AND_NOTIFY(translateY, translateY);
+            VD_SET_PRIMITIVE_FIELD_AND_NOTIFY(translateY, translateY);
         }
         void updateProperties(float rotate, float pivotX, float pivotY,
                 float scaleX, float scaleY, float translateX, float translateY) {
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index ab66b2a..890d4a1 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -113,18 +113,11 @@
         mBufferPreserved = mEglManager.setPreserveBuffer(mEglSurface, preserveBuffer);
         mHaveNewSurface = true;
         mSwapHistory.clear();
-        makeCurrent();
     } else {
         mRenderThread.removeFrameCallback(this);
     }
 }
 
-void CanvasContext::requireSurface() {
-    LOG_ALWAYS_FATAL_IF(mEglSurface == EGL_NO_SURFACE,
-            "requireSurface() called but no surface set!");
-    makeCurrent();
-}
-
 void CanvasContext::setSwapBehavior(SwapBehavior swapBehavior) {
     mSwapBehavior = swapBehavior;
 }
@@ -146,6 +139,18 @@
     return mRenderThread.removeFrameCallback(this);
 }
 
+void CanvasContext::setStopped(bool stopped) {
+    if (mStopped != stopped) {
+        mStopped = stopped;
+        if (mStopped) {
+            mRenderThread.removeFrameCallback(this);
+            if (mEglManager.isCurrent(mEglSurface)) {
+                mEglManager.makeCurrent(EGL_NO_SURFACE);
+            }
+        }
+    }
+}
+
 // TODO: don't pass viewport size, it's automatic via EGL
 void CanvasContext::setup(int width, int height, float lightRadius,
         uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
@@ -172,7 +177,9 @@
     mOpaque = opaque;
 }
 
-void CanvasContext::makeCurrent() {
+bool CanvasContext::makeCurrent() {
+    if (mStopped) return false;
+
     // TODO: Figure out why this workaround is needed, see b/13913604
     // In the meantime this matches the behavior of GLRenderer, so it is not a regression
     EGLint error = 0;
@@ -180,6 +187,7 @@
     if (error) {
         setSurface(nullptr);
     }
+    return !error;
 }
 
 static bool wasSkipped(FrameInfo* info) {
@@ -671,7 +679,7 @@
 }
 
 Layer* CanvasContext::createTextureLayer() {
-    requireSurface();
+    mEglManager.initialize();
     return LayerRenderer::createTextureLayer(mRenderThread.renderState());
 }
 
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index 9350114..52df3abe 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -82,13 +82,14 @@
     void initialize(Surface* surface);
     void updateSurface(Surface* surface);
     bool pauseSurface(Surface* surface);
+    void setStopped(bool stopped);
     bool hasSurface() { return mNativeSurface.get(); }
 
     void setup(int width, int height, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     void setLightCenter(const Vector3& lightCenter);
     void setOpaque(bool opaque);
-    void makeCurrent();
+    bool makeCurrent();
     void prepareTree(TreeInfo& info, int64_t* uiFrameInfo,
             int64_t syncQueued, RenderNode* target);
     void draw();
@@ -172,7 +173,6 @@
     friend class android::uirenderer::RenderState;
 
     void setSurface(Surface* window);
-    void requireSurface();
 
     void freePrefetchedLayers(TreeObserver* observer);
 
@@ -185,6 +185,7 @@
     EglManager& mEglManager;
     sp<Surface> mNativeSurface;
     EGLSurface mEglSurface = EGL_NO_SURFACE;
+    bool mStopped = false;
     bool mBufferPreserved = false;
     SwapBehavior mSwapBehavior = kSwap_default;
     struct SwapHistory {
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 651aaa2..ed472ac 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -115,7 +115,7 @@
     ATRACE_CALL();
     int64_t vsync = mFrameInfo[static_cast<int>(FrameInfoIndex::Vsync)];
     mRenderThread->timeLord().vsyncReceived(vsync);
-    mContext->makeCurrent();
+    bool canDraw = mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse(mContext);
 
     for (size_t i = 0; i < mLayers.size(); i++) {
@@ -126,8 +126,9 @@
 
     // This is after the prepareTree so that any pending operations
     // (RenderNode tree state, prefetched layers, etc...) will be flushed.
-    if (CC_UNLIKELY(!mContext->hasSurface())) {
+    if (CC_UNLIKELY(!mContext->hasSurface() || !canDraw)) {
         mSyncResult |= kSync_LostSurfaceRewardIfFound;
+        info.out.canDrawThisFrame = false;
     }
 
     if (info.out.hasAnimations) {
diff --git a/libs/hwui/renderthread/EglManager.cpp b/libs/hwui/renderthread/EglManager.cpp
index 8def7ad..ac6a28f 100644
--- a/libs/hwui/renderthread/EglManager.cpp
+++ b/libs/hwui/renderthread/EglManager.cpp
@@ -270,12 +270,6 @@
         // Ensure we always have a valid surface & context
         surface = mPBufferSurface;
     }
-    // TODO: Temporary to help diagnose b/27286867
-    if (mCurrentSurface == mPBufferSurface || surface == mPBufferSurface) {
-        ALOGD("Switching from surface %p%s to %p%s", mCurrentSurface,
-                mCurrentSurface == mPBufferSurface ? " (pbuffer)" : "",
-                        surface, surface == mPBufferSurface ? " (pbuffer)" : "");
-    }
     if (!eglMakeCurrent(mEglDisplay, surface, surface, mEglContext)) {
         if (errOut) {
             *errOut = eglGetError();
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 096093c..5e37856 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -168,6 +168,18 @@
     return (bool) postAndWait(task);
 }
 
+CREATE_BRIDGE2(setStopped, CanvasContext* context, bool stopped) {
+    args->context->setStopped(args->stopped);
+    return nullptr;
+}
+
+void RenderProxy::setStopped(bool stopped) {
+    SETUP_TASK(setStopped);
+    args->context = mContext;
+    args->stopped = stopped;
+    postAndWait(task);
+}
+
 CREATE_BRIDGE6(setup, CanvasContext* context, int width, int height,
         float lightRadius, uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
     args->context->setup(args->width, args->height, args->lightRadius,
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index 98aace0..c39319d 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -79,6 +79,7 @@
     ANDROID_API void initialize(const sp<Surface>& surface);
     ANDROID_API void updateSurface(const sp<Surface>& surface);
     ANDROID_API bool pauseSurface(const sp<Surface>& surface);
+    ANDROID_API void setStopped(bool stopped);
     ANDROID_API void setup(int width, int height, float lightRadius,
             uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
     ANDROID_API void setLightCenter(const Vector3& lightCenter);
diff --git a/libs/hwui/tests/microbench/PathParserBench.cpp b/libs/hwui/tests/microbench/PathParserBench.cpp
index 4186539..b43c4c3 100644
--- a/libs/hwui/tests/microbench/PathParserBench.cpp
+++ b/libs/hwui/tests/microbench/PathParserBench.cpp
@@ -31,7 +31,7 @@
     size_t length = strlen(sPathString);
     PathParser::ParseResult result;
     while (state.KeepRunning()) {
-        PathParser::parseStringForSkPath(&skPath, &result, sPathString, length);
+        PathParser::parseAsciiStringForSkPath(&skPath, &result, sPathString, length);
         benchmark::DoNotOptimize(&result);
         benchmark::DoNotOptimize(&skPath);
     }
@@ -43,7 +43,7 @@
     PathData outData;
     PathParser::ParseResult result;
     while (state.KeepRunning()) {
-        PathParser::getPathDataFromString(&outData, &result, sPathString, length);
+        PathParser::getPathDataFromAsciiString(&outData, &result, sPathString, length);
         benchmark::DoNotOptimize(&result);
         benchmark::DoNotOptimize(&outData);
     }
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index b864703..54ca68d 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -132,6 +132,7 @@
         auto serializedClip = area.serializeClip(allocator);
         ASSERT_NE(nullptr, serializedClip);
         ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
+        ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
         EXPECT_EQ(Rect(200, 200), serializedClip->rect);
         EXPECT_EQ(serializedClip, area.serializeClip(allocator))
                 << "Requery of clip on unmodified ClipArea must return same pointer.";
@@ -145,6 +146,7 @@
         auto serializedClip = area.serializeClip(allocator);
         ASSERT_NE(nullptr, serializedClip);
         ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
+        ASSERT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
         auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
         EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
         EXPECT_EQ(Rect(37, 54, 145, 163), clipRectList->rect);
@@ -160,6 +162,7 @@
         auto serializedClip = area.serializeClip(allocator);
         ASSERT_NE(nullptr, serializedClip);
         ASSERT_EQ(ClipMode::Region, serializedClip->mode);
+        ASSERT_TRUE(serializedClip->intersectWithRoot) << "Replace op, so expect intersectWithRoot";
         auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
         EXPECT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
                 << "Clip region should be 200x200";
@@ -169,6 +172,18 @@
     }
 }
 
+TEST(ClipArea, serializeClip_pathIntersectWithRoot) {
+    ClipArea area(createClipArea());
+    LinearAllocator allocator;
+    SkPath circlePath;
+    circlePath.addCircle(100, 100, 100);
+    area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kIntersect_Op);
+
+    auto serializedClip = area.serializeClip(allocator);
+    ASSERT_NE(nullptr, serializedClip);
+    EXPECT_FALSE(serializedClip->intersectWithRoot) << "No replace, so no intersectWithRoot";
+}
+
 TEST(ClipArea, serializeIntersectedClip) {
     ClipArea area(createClipArea());
     LinearAllocator allocator;
diff --git a/libs/hwui/tests/unit/VectorDrawableTests.cpp b/libs/hwui/tests/unit/VectorDrawableTests.cpp
index 796169e..83b485f 100644
--- a/libs/hwui/tests/unit/VectorDrawableTests.cpp
+++ b/libs/hwui/tests/unit/VectorDrawableTests.cpp
@@ -234,9 +234,10 @@
     {"3e...3", false}, // Not starting with a verb and ill-formatted float
     {"L.M.F.A.O", false}, // No floats following verbs
     {"m 1 1", true}, // Valid path data
-    {"z", true}, // Valid path data
+    {"\n \t   z", true}, // Valid path data with leading spaces
     {"1-2e34567", false}, // Not starting with a verb and ill-formatted float
-    {"f 4 5", false} // Invalid verb
+    {"f 4 5", false}, // Invalid verb
+    {"\r      ", false} // Empty string
 };
 
 
@@ -250,7 +251,7 @@
         // Test generated path data against the given data.
         PathData pathData;
         size_t length = strlen(testData.pathString);
-        PathParser::getPathDataFromString(&pathData, &result, testData.pathString, length);
+        PathParser::getPathDataFromAsciiString(&pathData, &result, testData.pathString, length);
         EXPECT_EQ(testData.pathData, pathData);
     }
 
@@ -258,7 +259,7 @@
         PathParser::ParseResult result;
         PathData pathData;
         SkPath skPath;
-        PathParser::getPathDataFromString(&pathData, &result,
+        PathParser::getPathDataFromAsciiString(&pathData, &result,
                 stringPath.stringPath, strlen(stringPath.stringPath));
         EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
     }
@@ -274,13 +275,13 @@
     }
 }
 
-TEST(PathParser, parseStringForSkPath) {
+TEST(PathParser, parseAsciiStringForSkPath) {
     for (TestData testData: sTestDataSet) {
         PathParser::ParseResult result;
         size_t length = strlen(testData.pathString);
         // Check the return value as well as the SkPath generated.
         SkPath actualPath;
-        PathParser::parseStringForSkPath(&actualPath, &result, testData.pathString, length);
+        PathParser::parseAsciiStringForSkPath(&actualPath, &result, testData.pathString, length);
         bool hasValidData = !result.failureOccurred;
         EXPECT_EQ(hasValidData, testData.pathData.verbs.size() > 0);
         SkPath expectedPath;
@@ -291,7 +292,7 @@
     for (StringPath stringPath : sStringPaths) {
         PathParser::ParseResult result;
         SkPath skPath;
-        PathParser::parseStringForSkPath(&skPath, &result, stringPath.stringPath,
+        PathParser::parseAsciiStringForSkPath(&skPath, &result, stringPath.stringPath,
                 strlen(stringPath.stringPath));
         EXPECT_EQ(stringPath.isValid, !result.failureOccurred);
     }
@@ -390,5 +391,40 @@
         EXPECT_EQ(matrixAndScale.matrixScale, actualMatrixScale);
     }
 }
+
+TEST(VectorDrawable, groupProperties) {
+    //TODO: Also need to test property sync and dirty flag when properties change.
+    VectorDrawable::Group group;
+    VectorDrawable::Group::GroupProperties* properties = group.mutateProperties();
+    // Test default values, change values through setters and verify the change through getters.
+    EXPECT_EQ(0.0f, properties->getTranslateX());
+    properties->setTranslateX(1.0f);
+    EXPECT_EQ(1.0f, properties->getTranslateX());
+
+    EXPECT_EQ(0.0f, properties->getTranslateY());
+    properties->setTranslateY(1.0f);
+    EXPECT_EQ(1.0f, properties->getTranslateY());
+
+    EXPECT_EQ(0.0f, properties->getRotation());
+    properties->setRotation(1.0f);
+    EXPECT_EQ(1.0f, properties->getRotation());
+
+    EXPECT_EQ(1.0f, properties->getScaleX());
+    properties->setScaleX(0.0f);
+    EXPECT_EQ(0.0f, properties->getScaleX());
+
+    EXPECT_EQ(1.0f, properties->getScaleY());
+    properties->setScaleY(0.0f);
+    EXPECT_EQ(0.0f, properties->getScaleY());
+
+    EXPECT_EQ(0.0f, properties->getPivotX());
+    properties->setPivotX(1.0f);
+    EXPECT_EQ(1.0f, properties->getPivotX());
+
+    EXPECT_EQ(0.0f, properties->getPivotY());
+    properties->setPivotY(1.0f);
+    EXPECT_EQ(1.0f, properties->getPivotY());
+
+}
 }; // namespace uirenderer
 }; // namespace android
diff --git a/media/java/android/media/tv/TvContract.java b/media/java/android/media/tv/TvContract.java
index e8c50e3..db7b43a 100644
--- a/media/java/android/media/tv/TvContract.java
+++ b/media/java/android/media/tv/TvContract.java
@@ -1217,6 +1217,18 @@
         public static final String COLUMN_SEARCHABLE = "searchable";
 
         /**
+         * The flag indicating whether recording of this program is prohibited.
+         *
+         * <p>A value of 1 indicates that recording of this program is prohibited and application
+         * will not schedule any recording for this program. A value of 0 indicates that the
+         * recording is not prohibited. If not specified, this value is set to 0 (not prohibited) by
+         * default.
+         *
+         * <p>Type: INTEGER (boolean)
+         */
+        public static final String COLUMN_RECORDING_PROHIBITED = "recording_prohibited";
+
+        /**
          * Internal data used by individual TV input services.
          *
          * <p>This is internal to the provider that inserted it, and should not be decoded by other
diff --git a/media/java/android/media/tv/TvInputInfo.java b/media/java/android/media/tv/TvInputInfo.java
index 0b64876..a33b219 100644
--- a/media/java/android/media/tv/TvInputInfo.java
+++ b/media/java/android/media/tv/TvInputInfo.java
@@ -16,7 +16,9 @@
 
 package android.media.tv;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
+import android.annotation.StringRes;
 import android.annotation.SystemApi;
 import android.content.ComponentName;
 import android.content.Context;
@@ -48,6 +50,8 @@
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Locale;
@@ -62,6 +66,12 @@
     private static final boolean DEBUG = false;
     private static final String TAG = "TvInputInfo";
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TYPE_TUNER, TYPE_OTHER, TYPE_COMPOSITE, TYPE_SVIDEO, TYPE_SCART, TYPE_COMPONENT,
+            TYPE_VGA, TYPE_DVI, TYPE_HDMI, TYPE_DISPLAY_PORT})
+    public @interface Type {}
+
     // Should be in sync with frameworks/base/core/res/res/values/attrs.xml
     /**
      * TV input type: the TV input service is a tuner which provides channels.
@@ -343,6 +353,7 @@
     /**
      * Returns the type of this TV input.
      */
+    @Type
     public int getType() {
         return mType;
     }
@@ -768,7 +779,7 @@
          * @hide
          */
         @SystemApi
-        public Builder setLabel(int resId) {
+        public Builder setLabel(@StringRes int resId) {
             if (mLabel != null) {
                 throw new IllegalStateException("Label text is already set.");
             }
diff --git a/media/java/android/media/tv/TvInputManager.java b/media/java/android/media/tv/TvInputManager.java
index b4536b1..bfd938e 100644
--- a/media/java/android/media/tv/TvInputManager.java
+++ b/media/java/android/media/tv/TvInputManager.java
@@ -99,6 +99,13 @@
      */
     public static final int DVB_DEVICE_FRONTEND = DVB_DEVICE_END;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
+            VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
+            VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
+    public @interface VideoUnavailableReason {}
+
     static final int VIDEO_UNAVAILABLE_REASON_START = 0;
     static final int VIDEO_UNAVAILABLE_REASON_END = 4;
 
@@ -135,10 +142,9 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({VIDEO_UNAVAILABLE_REASON_UNKNOWN, VIDEO_UNAVAILABLE_REASON_TUNING,
-            VIDEO_UNAVAILABLE_REASON_WEAK_SIGNAL, VIDEO_UNAVAILABLE_REASON_BUFFERING,
-            VIDEO_UNAVAILABLE_REASON_AUDIO_ONLY})
-    public @interface VideoUnavailableReason {}
+    @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
+            TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
+    public @interface TimeShiftStatus {}
 
     /**
      * Status for {@link TvInputService.Session#notifyTimeShiftStatusChanged(int)} and
@@ -169,12 +175,6 @@
      */
     public static final int TIME_SHIFT_STATUS_AVAILABLE = 3;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({TIME_SHIFT_STATUS_UNKNOWN, TIME_SHIFT_STATUS_UNSUPPORTED,
-            TIME_SHIFT_STATUS_UNAVAILABLE, TIME_SHIFT_STATUS_AVAILABLE})
-    public @interface TimeShiftStatus {}
-
     /**
      * Value returned by {@link TvInputService.Session#onTimeShiftGetCurrentPosition()} and
      * {@link TvInputService.Session#onTimeShiftGetStartPosition()} when time shifting has not
@@ -182,6 +182,12 @@
      */
     public static final long TIME_SHIFT_INVALID_TIME = Long.MIN_VALUE;
 
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
+            RECORDING_ERROR_RESOURCE_BUSY})
+    public @interface RecordingError {}
+
     /**
      * Error for {@link TvInputService.RecordingSession#notifyError(int)} and
      * {@link TvRecordingClient.RecordingCallback#onError(int)}: The requested operation cannot be
@@ -205,9 +211,8 @@
 
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
-    @IntDef({RECORDING_ERROR_UNKNOWN, RECORDING_ERROR_INSUFFICIENT_SPACE,
-            RECORDING_ERROR_RESOURCE_BUSY})
-    public @interface RecordingError {}
+    @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
+    public @interface InputState {}
 
     /**
      * State for {@link #getInputState(String)} and
@@ -240,11 +245,6 @@
      */
     public static final int INPUT_STATE_DISCONNECTED = 2;
 
-    /** @hide */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({INPUT_STATE_CONNECTED, INPUT_STATE_CONNECTED_STANDBY, INPUT_STATE_DISCONNECTED})
-    public @interface InputState {}
-
     /**
      * Broadcast intent action when the user blocked content ratings change. For use with the
      * {@link #isRatingBlocked}.
@@ -483,26 +483,19 @@
         }
 
         /**
-         * This is called when the start playback position is changed.
-         *
-         * <p>The start playback position of the time shifted program should be adjusted when the TV
-         * input cannot retain the whole recorded program due to some reason (e.g. limitation on
-         * storage space). This is necessary to prevent the application from allowing the user to
-         * seek to a time position that is not reachable.
+         * This is called when the start position for time shifting has changed.
          *
          * @param session A {@link TvInputManager.Session} associated with this callback.
-         * @param timeMs The start playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftStartPositionChanged(Session session, long timeMs) {
         }
 
         /**
-         * This is called when the current playback position is changed.
+         * This is called when the current position for time shifting is changed.
          *
          * @param session A {@link TvInputManager.Session} associated with this callback.
-         * @param timeMs The current playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftCurrentPositionChanged(Session session, long timeMs) {
         }
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 97ef6d8..e134635 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.FloatRange;
 import android.annotation.MainThread;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -823,7 +824,7 @@
          *
          * @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
          */
-        public abstract void onSetStreamVolume(float volume);
+        public abstract void onSetStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume);
 
         /**
          * Tunes to a given channel.
@@ -995,15 +996,18 @@
         }
 
         /**
-         * Returns the start playback position for time shifting, in milliseconds since the epoch.
+         * Returns the start position for time shifting, in milliseconds since the epoch.
          * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
          * moment.
          *
-         * <p>The start playback position of the time shifted program should be adjusted when the
-         * implementation cannot retain the whole recorded program due to some reason (e.g.
-         * limitation on storage space). It is the earliest possible time position that the user can
-         * seek to, thus failure to notifying its change immediately might result in bad experience
-         * where the application allows the user to seek to an invalid time position.
+         * <p>The start position for time shifting indicates the earliest possible time the user can
+         * seek to. Initially this is equivalent to the time when the implementation starts
+         * recording. Later it may be adjusted because there is insufficient space or the duration
+         * of recording is limited by the implementation. The application does not allow the user to
+         * seek to a position earlier than the start position.
+         *
+         * <p>For playback of a recorded program initiated by {@link #onTimeShiftPlay(Uri)}, the
+         * start position is the time when playback starts. It does not change.
          *
          * @see #onTimeShiftPlay(Uri)
          * @see #onTimeShiftResume()
@@ -1017,13 +1021,13 @@
         }
 
         /**
-         * Returns the current playback position for time shifting, in milliseconds since the epoch.
+         * Returns the current position for time shifting, in milliseconds since the epoch.
          * Returns {@link TvInputManager#TIME_SHIFT_INVALID_TIME} if the position is unknown at the
          * moment.
          *
-         * <p>Note that the current playback position should be equal to or greater than the start
-         * playback position reported by {@link #onTimeShiftGetStartPosition}. Failure to notifying
-         * the correct current position might lead to bad user experience.
+         * <p>The current position for time shifting is the same as the current position of
+         * playback. It should be equal to or greater than the start position reported by
+         * {@link #onTimeShiftGetStartPosition()}.
          *
          * @see #onTimeShiftPlay(Uri)
          * @see #onTimeShiftResume()
diff --git a/media/java/android/media/tv/TvTrackInfo.java b/media/java/android/media/tv/TvTrackInfo.java
index d718a7e..c9c881c 100644
--- a/media/java/android/media/tv/TvTrackInfo.java
+++ b/media/java/android/media/tv/TvTrackInfo.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.os.Bundle;
 import android.os.Parcel;
@@ -24,12 +25,20 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.Objects;
 
 /**
  * Encapsulates the format of tracks played in {@link TvInputService}.
  */
 public final class TvTrackInfo implements Parcelable {
+
+    /** @hide */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({TYPE_AUDIO, TYPE_VIDEO, TYPE_SUBTITLE})
+    public @interface Type {}
+
     /**
      * The type value for audio tracks.
      */
@@ -96,6 +105,7 @@
      * Returns the type of the track. The type should be one of the followings:
      * {@link #TYPE_AUDIO}, {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}.
      */
+    @Type
     public final int getType() {
         return mType;
     }
@@ -319,7 +329,7 @@
          * @throws IllegalArgumentException if the type is not any of {@link #TYPE_AUDIO},
          *                                  {@link #TYPE_VIDEO} and {@link #TYPE_SUBTITLE}
          */
-        public Builder(int type, @NonNull String id) {
+        public Builder(@Type int type, @NonNull String id) {
             if (type != TYPE_AUDIO
                     && type != TYPE_VIDEO
                     && type != TYPE_SUBTITLE) {
diff --git a/media/java/android/media/tv/TvView.java b/media/java/android/media/tv/TvView.java
index 02ee0cc..10cec1f 100644
--- a/media/java/android/media/tv/TvView.java
+++ b/media/java/android/media/tv/TvView.java
@@ -16,6 +16,7 @@
 
 package android.media.tv;
 
+import android.annotation.FloatRange;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
@@ -271,7 +272,7 @@
      *
      * @param volume A volume value between {@code 0.0f} to {@code 1.0f}.
      */
-    public void setStreamVolume(float volume) {
+    public void setStreamVolume(@FloatRange(from = 0.0, to = 1.0) float volume) {
         if (DEBUG) Log.d(TAG, "setStreamVolume(" + volume + ")");
         mStreamVolume = volume;
         if (mSession == null) {
@@ -847,32 +848,34 @@
     public abstract static class TimeShiftPositionCallback {
 
         /**
-         * This is called when the start playback position is changed.
+         * This is called when the start position for time shifting has changed.
          *
-         * <p>The start playback position of the time shifted program can be adjusted by the TV
-         * input when it cannot retain the whole recorded program due to some reason (e.g.
-         * limitation on storage space). The application should not allow the user to seek to a
-         * position earlier than the start position.
+         * <p>The start position for time shifting indicates the earliest possible time the user can
+         * seek to. Initially this is equivalent to the time when the underlying TV input starts
+         * recording. Later it may be adjusted because there is insufficient space or the duration
+         * of recording is limited. The application must not allow the user to seek to a position
+         * earlier than the start position.
          *
-         * <p>Note that {@code timeMs} is not relative time in the program but wall-clock time,
-         * which is intended to avoid calling this method unnecessarily around program boundaries.
+         * <p>For playback of a recorded program initiated by {@link #timeShiftPlay(String, Uri)},
+         * the start position is the time when playback starts. It does not change.
          *
          * @param inputId The ID of the TV input bound to this view.
-         * @param timeMs The start playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The start position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftStartPositionChanged(String inputId, long timeMs) {
         }
 
         /**
-         * This is called when the current playback position is changed.
+         * This is called when the current position for time shifting has changed.
          *
-         * <p>Note that {@code timeMs} is not relative time in the program but wall-clock time,
-         * which is intended to avoid calling this method unnecessarily around program boundaries.
+         * <p>The current position for time shifting is the same as the current position of
+         * playback. During playback, the current position changes continuously. When paused, it
+         * does not change.
+         *
+         * <p>Note that {@code timeMs} is wall-clock time.
          *
          * @param inputId The ID of the TV input bound to this view.
-         * @param timeMs The current playback position of the time shifted program, in milliseconds
-         *            since the epoch.
+         * @param timeMs The current position for time shifting, in milliseconds since the epoch.
          */
         public void onTimeShiftCurrentPositionChanged(String inputId, long timeMs) {
         }
diff --git a/media/jni/soundpool/SoundPoolThread.h b/media/jni/soundpool/SoundPoolThread.h
index d388388..9096aeb 100644
--- a/media/jni/soundpool/SoundPoolThread.h
+++ b/media/jni/soundpool/SoundPoolThread.h
@@ -47,7 +47,7 @@
     void write(SoundPoolMsg msg);
 
 private:
-    static const size_t maxMessages = 5;
+    static const size_t maxMessages = 128;
 
     static int beginThread(void* arg);
     int run();
diff --git a/packages/DocumentsUI/Android.mk b/packages/DocumentsUI/Android.mk
index 3197abd..568e200 100644
--- a/packages/DocumentsUI/Android.mk
+++ b/packages/DocumentsUI/Android.mk
@@ -2,6 +2,7 @@
 include $(CLEAR_VARS)
 
 LOCAL_MODULE_TAGS := optional
+LOCAL_PRIVILEGED_MODULE := true
 
 LOCAL_SRC_FILES := $(call all-java-files-under, src)
 
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
index 15bfc3b..059b5e0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DocumentClipper.java
@@ -32,6 +32,7 @@
 import libcore.io.IoUtils;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -76,7 +77,8 @@
      * This should be run from inside an AsyncTask.
      */
     public List<DocumentInfo> getClippedDocuments() {
-        return getDocumentsFromClipData(mClipboard.getPrimaryClip());
+        ClipData data = mClipboard.getPrimaryClip();
+        return data == null ? Collections.EMPTY_LIST : getDocumentsFromClipData(data);
     }
 
     /**
diff --git a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
index f3b750a..d830c61 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/SaveFragment.java
@@ -84,6 +84,13 @@
                 new View.OnKeyListener() {
                     @Override
                     public boolean onKey(View v, int keyCode, KeyEvent event) {
+                        // Only handle key-down events. This is simpler, consistent with most other
+                        // UIs, and enables the handling of repeated key events from holding down a
+                        // key.
+                        if (event.getAction() != KeyEvent.ACTION_DOWN) {
+                            return false;
+                        }
+
                         if (keyCode == KeyEvent.KEYCODE_ENTER && mSave.isEnabled()) {
                             performSave();
                             return true;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index e7b2ed1..ccb2886 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -524,6 +524,7 @@
             }
 
             if (mActionMode != null) {
+                assert(!mSelected.isEmpty());
                 final String title = Shared.getQuantityString(getActivity(),
                         R.plurals.elements_selected, mSelected.size());
                 mActionMode.setTitle(title);
@@ -809,6 +810,8 @@
                                 // the user cancels the delete.
                                 if (mActionMode != null) {
                                     mActionMode.finish();
+                                } else {
+                                    Log.w(TAG, "Action mode is null before deleting documents.");
                                 }
                                 // Hide the files in the UI...since the operation
                                 // might be queued up on FileOperationService.
@@ -1110,7 +1113,7 @@
         List<String> enabled = new ArrayList<String>();
         for (String id : mAdapter.getModelIds()) {
             Cursor cursor = getModel().getItem(id);
-            if (cursor != null) {
+            if (cursor == null) {
                 Log.w(TAG, "Skipping selection. Can't obtain cursor for modeId: " + id);
                 continue;
             }
@@ -1176,14 +1179,23 @@
                 case DragEvent.ACTION_DROP:
                     // After a drop event, always stop highlighting the target.
                     setDropTargetHighlight(v, false);
+
+                    ClipData clipData = event.getClipData();
+                    if (clipData == null) {
+                        Log.w(TAG, "Received invalid drop event with null clipdata. Ignoring.");
+                        return false;
+                    }
+
                     // Don't copy from the cwd into the cwd. Note: this currently doesn't work for
                     // multi-window drag, because localState isn't carried over from one process to
                     // another.
                     Object src = event.getLocalState();
                     DocumentInfo dst = getDestination(v);
                     if (Objects.equals(src, dst)) {
+                        if (DEBUG) Log.d(TAG, "Drop target same as source. Ignoring.");
                         return false;
                     }
+
                     // Recognize multi-window drag and drop based on the fact that localState is not
                     // carried between processes. It will stop working when the localsState behavior
                     // is changed. The info about window should be passed in the localState then.
@@ -1192,7 +1204,8 @@
                     Metrics.logUserAction(getContext(),
                             src == null ? Metrics.USER_ACTION_DRAG_N_DROP_MULTI_WINDOW
                                     : Metrics.USER_ACTION_DRAG_N_DROP);
-                    copyFromClipData(event.getClipData(), dst);
+
+                    copyFromClipData(clipData, dst);
                     return true;
             }
             return false;
@@ -1202,7 +1215,7 @@
             String id = getModelId(v);
             if (id != null) {
                 Cursor dstCursor = mModel.getItem(id);
-                if (dstCursor != null) {
+                if (dstCursor == null) {
                     Log.w(TAG, "Invalid destination. Can't obtain cursor for modelId: " + id);
                     return null;
                 }
@@ -1436,7 +1449,8 @@
                     // This has to be handled here instead of in a keyboard shortcut, because
                     // keyboard shortcuts all have to be modified with the 'Ctrl' key.
                     if (mSelectionManager.hasSelection()) {
-                        deleteDocuments(mSelectionManager.getSelection());
+                        Selection selection = mSelectionManager.getSelection(new Selection());
+                        deleteDocuments(selection);
                     }
                     // Always handle the key, even if there was nothing to delete. This is a
                     // precaution to prevent other handlers from potentially picking up the event
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
index 016cc9e..e6217b2 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/FragmentTuner.java
@@ -195,6 +195,10 @@
      */
     private static final class FilesTuner extends FragmentTuner {
 
+        // We use this to keep track of whether a model has been previously loaded or not so we can
+        // open the drawer on empty directories on first launch
+        private boolean mModelPreviousLoaded;
+
         public FilesTuner(Context context, State state) {
             super(context, state);
         }
@@ -230,10 +234,12 @@
         @Override
         void onModelLoaded(Model model, @ResultType int resultType, boolean isSearch) {
             // When launched into empty root, open drawer.
-            if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch) {
+            if (model.isEmpty() && !mState.hasInitialLocationChanged() && !isSearch
+                    && !mModelPreviousLoaded) {
                 // This noops on layouts without drawer, so no need to guard.
                 ((BaseActivity) mContext).setRootsDrawerOpen(true);
             }
+            mModelPreviousLoaded = true;
         }
 
         @Override
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
index 580fa38..871e135 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/FileOperationService.java
@@ -229,31 +229,32 @@
             @OpType int operationType, String id, List<DocumentInfo> srcs, DocumentInfo srcParent,
             DocumentStack stack) {
 
+        if (srcs.isEmpty()) {
+            Log.w(TAG, "Ignoring job request with empty srcs list. Id: " + id);
+            return null;
+        }
+
         if (mRunning.containsKey(id)) {
             Log.w(TAG, "Duplicate job id: " + id
                     + ". Ignoring job request for srcs: " + srcs + ", stack: " + stack + ".");
             return null;
         }
 
-        Job job = null;
         switch (operationType) {
             case OPERATION_COPY:
-                job = jobFactory.createCopy(this, getApplicationContext(), this, id, stack, srcs);
-                break;
+                return jobFactory.createCopy(
+                        this, getApplicationContext(), this, id, stack, srcs);
             case OPERATION_MOVE:
-                job = jobFactory.createMove(this, getApplicationContext(), this, id, stack, srcs,
+                return jobFactory.createMove(
+                        this, getApplicationContext(), this, id, stack, srcs,
                         srcParent);
-                break;
             case OPERATION_DELETE:
-                job = jobFactory.createDelete(this, getApplicationContext(), this, id, stack, srcs,
+                return jobFactory.createDelete(
+                        this, getApplicationContext(), this, id, stack, srcs,
                         srcParent);
-                break;
             default:
                 throw new UnsupportedOperationException();
         }
-
-        assert(job != null);
-        return job;
     }
 
     @GuardedBy("mRunning")
diff --git a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
index c723ac6..b4f1299 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/services/Job.java
@@ -291,18 +291,24 @@
 
         Job createCopy(Context service, Context appContext, Listener listener,
                 String id, DocumentStack stack, List<DocumentInfo> srcs) {
+            assert(!srcs.isEmpty());
+            assert(stack.peek().isCreateSupported());
             return new CopyJob(service, appContext, listener, id, stack, srcs);
         }
 
         Job createMove(Context service, Context appContext, Listener listener,
                 String id, DocumentStack stack, List<DocumentInfo> srcs,
                 DocumentInfo srcParent) {
+            assert(!srcs.isEmpty());
+            assert(stack.peek().isCreateSupported());
             return new MoveJob(service, appContext, listener, id, stack, srcs, srcParent);
         }
 
         Job createDelete(Context service, Context appContext, Listener listener,
                 String id, DocumentStack stack, List<DocumentInfo> srcs,
                 DocumentInfo srcParent) {
+            assert(!srcs.isEmpty());
+            assert(stack.peek().isDirectory());  // we can't currently delete from archives.
             return new DeleteJob(service, appContext, listener, id, stack, srcs, srcParent);
         }
     }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
index 4d5392e..96d963f 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/services/FileOperationServiceTest.java
@@ -79,6 +79,16 @@
         mJobFactory.assertAllJobsStarted();
     }
 
+    public void testRunsJobs_AfterExceptionInJobCreation() throws Exception {
+        startService(createCopyIntent(new ArrayList<DocumentInfo>(), BETA_DOC));
+        startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
+
+        mJobFactory.assertJobsCreated(1);
+
+        mExecutor.runAll();
+        mJobFactory.assertAllJobsStarted();
+    }
+
     public void testRunsJobs_AfterFailure() throws Exception {
         startService(createCopyIntent(newArrayList(ALPHA_DOC), BETA_DOC));
         startService(createCopyIntent(newArrayList(GAMMA_DOC), DELTA_DOC));
@@ -182,9 +192,18 @@
             }
         }
 
+        void assertJobsCreated(int expected) {
+            assertEquals(expected, jobs.size());
+        }
+
         @Override
         Job createCopy(Context service, Context appContext, Listener listener, String id,
                 DocumentStack stack, List<DocumentInfo> srcs) {
+
+            if (srcs.isEmpty()) {
+                throw new RuntimeException("Empty srcs not supported!");
+            }
+
             TestJob job = new TestJob(service, appContext, listener, OPERATION_COPY, id, stack);
             jobs.add(job);
             return job;
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 61966b2..09fec81 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -334,6 +334,14 @@
     <!-- An explanation text that the password needs to be entered since profiles have just been switched. [CHAR LIMIT=80] -->
     <string name="kg_prompt_reason_switch_profiles_password">Password required when you switch profiles</string>
 
+    <!-- An explanation text that the credential needs to be entered because a device admin has
+    locked the device. [CHAR LIMIT=80] -->
+    <string name="kg_prompt_reason_device_admin">Device administrator locked device</string>
+
+    <!-- An explanation text that the credential needs to be entered because the user has clicked
+     the force lock button. [CHAR LIMIT=80] -->
+    <string name="kg_prompt_reason_user_request">Device was locked manually</string>
+
     <!-- An explanation text that the pattern needs to be solved since it hasn't been solved in a while. [CHAR LIMIT=80]-->
     <plurals name="kg_prompt_reason_time_pattern">
         <item quantity="one">Device hasn\'t been unlocked for <xliff:g id="number">%d</xliff:g> hour. Confirm pattern.</item>
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
index 63dec8b..189f5b7 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPasswordView.java
@@ -117,6 +117,10 @@
                 return R.string.kg_prompt_reason_restart_password;
             case PROMPT_REASON_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_password;
+            case PROMPT_REASON_DEVICE_ADMIN:
+                return R.string.kg_prompt_reason_device_admin;
+            case PROMPT_REASON_USER_REQUEST:
+                return R.string.kg_prompt_reason_user_request;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
index be2701d..e070492 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPatternView.java
@@ -339,6 +339,14 @@
                 mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_timeout_pattern,
                         true /* important */);
                 break;
+            case PROMPT_REASON_DEVICE_ADMIN:
+                mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_device_admin,
+                        true /* important */);
+                break;
+            case PROMPT_REASON_USER_REQUEST:
+                mSecurityMessageDisplay.setMessage(R.string.kg_prompt_reason_user_request,
+                        true /* important */);
+                break;
             case PROMPT_REASON_NONE:
                 break;
             default:
diff --git a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
index fe98cb8..f14290a 100644
--- a/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
+++ b/packages/Keyguard/src/com/android/keyguard/KeyguardPinBasedInputView.java
@@ -108,6 +108,10 @@
                 return R.string.kg_prompt_reason_restart_pin;
             case PROMPT_REASON_TIMEOUT:
                 return R.string.kg_prompt_reason_timeout_pin;
+            case PROMPT_REASON_DEVICE_ADMIN:
+                return R.string.kg_prompt_reason_device_admin;
+            case PROMPT_REASON_USER_REQUEST:
+                return R.string.kg_prompt_reason_user_request;
             case PROMPT_REASON_NONE:
                 return 0;
             default:
diff --git a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
index e7aebdd..c411186 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/ui/PrintActivity.java
@@ -320,6 +320,8 @@
                 mFileProvider, new RemotePrintDocument.RemoteAdapterDeathObserver() {
             @Override
             public void onDied() {
+                Log.w(LOG_TAG, "Printing app died unexpectedly");
+
                 // If we are finishing or we are in a state that we do not need any
                 // data from the printing app, then no need to finish.
                 if (isFinishing() || (isFinalState(mState) && !mPrintedDocument.isUpdating())) {
diff --git a/packages/SettingsLib/res/layout/restricted_switch_preference.xml b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
new file mode 100644
index 0000000..89dc10b
--- /dev/null
+++ b/packages/SettingsLib/res/layout/restricted_switch_preference.xml
@@ -0,0 +1,86 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="match_parent"
+    android:layout_height="wrap_content"
+    android:minHeight="?android:attr/listPreferredItemHeightSmall"
+    android:gravity="center_vertical"
+    android:paddingStart="?android:attr/listPreferredItemPaddingStart"
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
+    android:background="?android:attr/activatedBackgroundIndicator"
+    android:clipToPadding="false">
+
+    <LinearLayout
+        android:id="@+id/icon_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:minWidth="60dp"
+        android:gravity="start|center_vertical"
+        android:orientation="horizontal"
+        android:paddingEnd="12dp"
+        android:paddingTop="4dp"
+        android:paddingBottom="4dp">
+        <com.android.internal.widget.PreferenceImageView
+            android:id="@android:id/icon"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:maxWidth="48dp"
+            android:maxHeight="48dp" />
+    </LinearLayout>
+
+    <RelativeLayout
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_weight="1"
+        android:paddingTop="16dp"
+        android:paddingBottom="16dp">
+
+        <TextView android:id="@android:id/title"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:singleLine="true"
+            android:textAppearance="?android:attr/textAppearanceListItem"
+            android:ellipsize="marquee" />
+
+        <TextView android:id="@android:id/summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/title"
+            android:layout_alignStart="@android:id/title"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10" />
+
+        <TextView android:id="@+id/additional_summary"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_below="@android:id/summary"
+            android:layout_alignStart="@android:id/summary"
+            android:textAppearance="?android:attr/textAppearanceListItemSecondary"
+            android:textColor="?android:attr/textColorSecondary"
+            android:maxLines="10"
+            android:visibility="gone" />
+    </RelativeLayout>
+
+    <!-- Preference should place its actual preference widget here. -->
+    <LinearLayout android:id="@android:id/widget_frame"
+        android:layout_width="wrap_content"
+        android:layout_height="match_parent"
+        android:gravity="end|center_vertical"
+        android:paddingStart="16dp"
+        android:orientation="vertical" />
+
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SettingsLib/res/values/attrs.xml b/packages/SettingsLib/res/values/attrs.xml
index 4484613..4cdc177 100644
--- a/packages/SettingsLib/res/values/attrs.xml
+++ b/packages/SettingsLib/res/values/attrs.xml
@@ -15,10 +15,18 @@
 -->
 
 <resources>
+
     <declare-styleable name="RestrictedPreference">
+        <!-- The user restriction on which the preference disabled by admin state will be based on. -->
         <attr name="userRestriction" format="string" />
+        <!-- If true then we can use enabled/disabled by admin strings for summary (android.R.id.summary). -->
         <attr name="useAdminDisabledSummary" format="boolean" />
+        <!-- If true, an additional summary will be added in addition to the existing summary and
+        this will be used for enabled/disabled by admin strings leaving android.R.id.summary untouched.
+        As such when this is true, useAdminDisabledSummary will be overwritten to false. -->
+        <attr name="useAdditionalSummary" format="boolean" />
     </declare-styleable>
+
     <declare-styleable name="WifiEncryptionState">
         <attr name="state_encrypted" format="boolean" />
     </declare-styleable>
diff --git a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
index f381286..dabbc61 100644
--- a/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
+++ b/packages/SettingsLib/src/com/android/settingslib/RestrictedSwitchPreference.java
@@ -17,12 +17,14 @@
 package com.android.settingslib;
 
 import android.content.Context;
+import android.content.res.TypedArray;
 import android.os.UserHandle;
 import android.support.v4.content.res.TypedArrayUtils;
 import android.support.v7.preference.PreferenceManager;
 import android.support.v7.preference.PreferenceViewHolder;
 import android.support.v14.preference.SwitchPreference;
 import android.util.AttributeSet;
+import android.util.TypedValue;
 import android.view.View;
 import android.widget.TextView;
 
@@ -34,12 +36,28 @@
  */
 public class RestrictedSwitchPreference extends SwitchPreference {
     RestrictedPreferenceHelper mHelper;
+    boolean mUseAdditionalSummary = false;
 
     public RestrictedSwitchPreference(Context context, AttributeSet attrs,
             int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
         setWidgetLayoutResource(R.layout.restricted_switch_widget);
         mHelper = new RestrictedPreferenceHelper(context, this, attrs);
+        if (attrs != null) {
+            final TypedArray attributes = context.obtainStyledAttributes(attrs,
+                    R.styleable.RestrictedPreference);
+            final TypedValue useAdditionalSummary =
+                    attributes.peekValue(R.styleable.RestrictedPreference_useAdditionalSummary);
+            if (useAdditionalSummary != null) {
+                mUseAdditionalSummary =
+                        (useAdditionalSummary.type == TypedValue.TYPE_INT_BOOLEAN
+                                && useAdditionalSummary.data != 0);
+            }
+        }
+        if (mUseAdditionalSummary) {
+            setLayoutResource(R.layout.restricted_switch_preference);
+            useAdminDisabledSummary(false);
+        }
     }
 
     public RestrictedSwitchPreference(Context context, AttributeSet attrs, int defStyleAttr) {
@@ -67,11 +85,29 @@
         if (switchWidget != null) {
             switchWidget.setVisibility(isDisabledByAdmin() ? View.GONE : View.VISIBLE);
         }
-        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
-        if (summaryView != null && isDisabledByAdmin()) {
-            summaryView.setText(
-                    isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
-            summaryView.setVisibility(View.VISIBLE);
+        if (mUseAdditionalSummary) {
+            final TextView additionalSummaryView = (TextView) holder.findViewById(
+                    R.id.additional_summary);
+            if (additionalSummaryView != null) {
+                if (isDisabledByAdmin()) {
+                    additionalSummaryView.setText(
+                            isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+                    additionalSummaryView.setVisibility(View.VISIBLE);
+                }
+            } else {
+                additionalSummaryView.setVisibility(View.GONE);
+            }
+        } else {
+            final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);
+            if (summaryView != null) {
+                if (isDisabledByAdmin()) {
+                    summaryView.setText(
+                            isChecked() ? R.string.enabled_by_admin : R.string.disabled_by_admin);
+                    summaryView.setVisibility(View.VISIBLE);
+                }
+            }
+            // No need to change the visibility to GONE in the else case here since Preference class
+            // would have already changed it if there is no summary to display.
         }
     }
 
diff --git a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
index 8881034..8c2af45 100644
--- a/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
+++ b/packages/SettingsLib/src/com/android/settingslib/applications/ApplicationsState.java
@@ -839,8 +839,18 @@
 
                     for (int i = 0; i < mEntriesMap.size(); i++) {
                         int userId = mEntriesMap.keyAt(i);
-                        List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(launchIntent,
-                                PackageManager.GET_DISABLED_COMPONENTS, userId);
+                        // If we do not specify MATCH_DIRECT_BOOT_AWARE or
+                        // MATCH_DIRECT_BOOT_UNAWARE, system will derive and update the flags
+                        // according to the user's lock state. When the user is locked, components
+                        // with ComponentInfo#directBootAware == false will be filtered. We should
+                        // explicitly include both direct boot aware and unaware components here.
+                        List<ResolveInfo> intents = mPm.queryIntentActivitiesAsUser(
+                                launchIntent,
+                                PackageManager.GET_DISABLED_COMPONENTS
+                                        | PackageManager.MATCH_DIRECT_BOOT_AWARE
+                                        | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
+                                userId
+                        );
                         synchronized (mEntriesMap) {
                             if (DEBUG_LOCKING) Log.v(TAG, "MSG_LOAD_LAUNCHER acquired lock");
                             HashMap<String, AppEntry> userEntries = mEntriesMap.valueAt(i);
@@ -1116,6 +1126,10 @@
 
         public boolean mounted;
 
+        /**
+         * Setting this to {@code true} prevents the entry to be filtered by
+         * {@link #FILTER_DOWNLOADED_AND_LAUNCHER}.
+         */
         public boolean hasLauncherEntry;
 
         public String getNormalizedLabel() {
@@ -1286,6 +1300,9 @@
         }
     };
 
+    /**
+     * Displays a combined list with "downloaded" and "visible in launcher" apps only.
+     */
     public static final AppFilter FILTER_DOWNLOADED_AND_LAUNCHER = new AppFilter() {
         public void init() {
         }
diff --git a/packages/Shell/res/layout/confirm_repeat.xml b/packages/Shell/res/layout/confirm_repeat.xml
index d12f467..ad90af1 100644
--- a/packages/Shell/res/layout/confirm_repeat.xml
+++ b/packages/Shell/res/layout/confirm_repeat.xml
@@ -38,5 +38,5 @@
         android:id="@android:id/checkbox"
         android:layout_width="match_parent"
         android:layout_height="wrap_content"
-        android:text="@string/bugreport_confirm_repeat" />
+        android:text="@string/bugreport_confirm_dont_repeat" />
 </LinearLayout>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
index bee15dd..95e36fd 100644
--- a/packages/Shell/res/values/strings.xml
+++ b/packages/Shell/res/values/strings.xml
@@ -35,9 +35,9 @@
     <string name="bugreport_finished_pending_screenshot_text" product="default">Tap to share your bug report without a screenshot or wait for the screenshot to finish</string>
 
     <!-- Body of dialog informing user about contents of a bugreport. [CHAR LIMIT=NONE] -->
-    <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, including personal and private information.  Only share bug reports with apps and people you trust.</string>
-    <!-- Checkbox that indicates this dialog should be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
-    <string name="bugreport_confirm_repeat">Show this message next time</string>
+    <string name="bugreport_confirm">Bug reports contain data from the system\'s various log files, which may include data you consider sensitive (such as app-usage and location data). Only share bug reports with people and apps you trust.</string>
+    <!-- Checkbox that indicates this dialog should not be shown again when the next bugreport is taken. [CHAR LIMIT=50] -->
+    <string name="bugreport_confirm_dont_repeat">Don\'t show again</string>
 
     <!-- Title for documents backend that offers bugreports. -->
     <string name="bugreport_storage_title">Bug reports</string>
diff --git a/packages/Shell/src/com/android/shell/BugreportPrefs.java b/packages/Shell/src/com/android/shell/BugreportPrefs.java
index 3748e89..93690d4 100644
--- a/packages/Shell/src/com/android/shell/BugreportPrefs.java
+++ b/packages/Shell/src/com/android/shell/BugreportPrefs.java
@@ -22,22 +22,24 @@
 /**
  * Preferences related to bug reports.
  */
-public class BugreportPrefs {
-    private static final String PREFS_BUGREPORT = "bugreports";
+final class BugreportPrefs {
+    static final String PREFS_BUGREPORT = "bugreports";
 
     private static final String KEY_WARNING_STATE = "warning-state";
 
-    public static final int STATE_UNKNOWN = 0;
-    public static final int STATE_SHOW = 1;
-    public static final int STATE_HIDE = 2;
+    static final int STATE_UNKNOWN = 0;
+    // Shows the warning dialog.
+    static final int STATE_SHOW = 1;
+    // Skips the warning dialog.
+    static final int STATE_HIDE = 2;
 
-    public static int getWarningState(Context context, int def) {
+    static int getWarningState(Context context, int def) {
         final SharedPreferences prefs = context.getSharedPreferences(
                 PREFS_BUGREPORT, Context.MODE_PRIVATE);
         return prefs.getInt(KEY_WARNING_STATE, def);
     }
 
-    public static void setWarningState(Context context, int value) {
+    static void setWarningState(Context context, int value) {
         final SharedPreferences prefs = context.getSharedPreferences(
                 PREFS_BUGREPORT, Context.MODE_PRIVATE);
         prefs.edit().putInt(KEY_WARNING_STATE, value).apply();
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index f0ddcb9..502eed1 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -17,7 +17,8 @@
 package com.android.shell;
 
 import static android.os.Process.THREAD_PRIORITY_BACKGROUND;
-import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
 import static com.android.shell.BugreportPrefs.getWarningState;
 
 import java.io.BufferedOutputStream;
@@ -927,7 +928,7 @@
         final Intent notifIntent;
 
         // Send through warning dialog by default
-        if (getWarningState(mContext, STATE_SHOW) == STATE_SHOW) {
+        if (getWarningState(mContext, STATE_UNKNOWN) != STATE_HIDE) {
             notifIntent = buildWarningIntent(mContext, sendIntent);
         } else {
             notifIntent = sendIntent;
diff --git a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
index a1d879a..da33a65 100644
--- a/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
+++ b/packages/Shell/src/com/android/shell/BugreportWarningActivity.java
@@ -59,7 +59,7 @@
         ap.mNegativeButtonListener = this;
 
         mConfirmRepeat = (CheckBox) ap.mView.findViewById(android.R.id.checkbox);
-        mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) == STATE_SHOW);
+        mConfirmRepeat.setChecked(getWarningState(this, STATE_UNKNOWN) != STATE_SHOW);
 
         setupAlert();
     }
@@ -68,7 +68,7 @@
     public void onClick(DialogInterface dialog, int which) {
         if (which == AlertDialog.BUTTON_POSITIVE) {
             // Remember confirm state, and launch target
-            setWarningState(this, mConfirmRepeat.isChecked() ? STATE_SHOW : STATE_HIDE);
+            setWarningState(this, mConfirmRepeat.isChecked() ? STATE_HIDE : STATE_SHOW);
             startActivity(mSendIntent);
         }
 
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 3eb7754..537e4c5 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -17,7 +17,14 @@
 package com.android.shell;
 
 import static android.test.MoreAsserts.assertContainsRegex;
+
 import static com.android.shell.ActionSendMultipleConsumerActivity.UI_NAME;
+import static com.android.shell.BugreportPrefs.PREFS_BUGREPORT;
+import static com.android.shell.BugreportPrefs.STATE_HIDE;
+import static com.android.shell.BugreportPrefs.STATE_SHOW;
+import static com.android.shell.BugreportPrefs.STATE_UNKNOWN;
+import static com.android.shell.BugreportPrefs.getWarningState;
+import static com.android.shell.BugreportPrefs.setWarningState;
 import static com.android.shell.BugreportProgressService.EXTRA_BUGREPORT;
 import static com.android.shell.BugreportProgressService.EXTRA_ID;
 import static com.android.shell.BugreportProgressService.EXTRA_MAX;
@@ -48,12 +55,12 @@
 import java.util.zip.ZipOutputStream;
 
 import libcore.io.Streams;
+
 import android.app.ActivityManager;
 import android.app.ActivityManager.RunningServiceInfo;
 import android.app.Instrumentation;
 import android.app.NotificationManager;
 import android.content.Context;
-import android.content.ContextWrapper;
 import android.content.Intent;
 import android.net.Uri;
 import android.os.Bundle;
@@ -62,7 +69,6 @@
 import android.support.test.uiautomator.UiDevice;
 import android.support.test.uiautomator.UiObject;
 import android.support.test.uiautomator.UiObjectNotFoundException;
-import android.support.test.uiautomator.UiSelector;
 import android.test.InstrumentationTestCase;
 import android.test.suitebuilder.annotation.LargeTest;
 import android.text.TextUtils;
@@ -70,7 +76,6 @@
 import android.util.Log;
 
 import com.android.shell.ActionSendMultipleConsumerActivity.CustomActionSendMultipleListener;
-import com.android.shell.BugreportProgressService;
 
 /**
  * Integration tests for {@link BugreportReceiver}.
@@ -168,7 +173,7 @@
         }
         mDescription = sb.toString();
 
-        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_HIDE);
+        setWarningState(mContext, STATE_HIDE);
     }
 
     public void testProgress() throws Exception {
@@ -500,9 +505,29 @@
         assertServiceNotRunning();
     }
 
-    public void testBugreportFinished_withWarning() throws Exception {
-        // Explicitly shows the warning.
-        BugreportPrefs.setWarningState(mContext, BugreportPrefs.STATE_SHOW);
+    public void testBugreportFinished_withWarningFirstTime() throws Exception {
+        bugreportFinishedWithWarningTest(null);
+    }
+
+    public void testBugreportFinished_withWarningUnknownState() throws Exception {
+        bugreportFinishedWithWarningTest(STATE_UNKNOWN);
+    }
+
+    public void testBugreportFinished_withWarningShowAgain() throws Exception {
+        bugreportFinishedWithWarningTest(STATE_SHOW);
+    }
+
+    private void bugreportFinishedWithWarningTest(Integer propertyState) throws Exception {
+        if (propertyState == null) {
+            // Clear properties
+            mContext.getSharedPreferences(PREFS_BUGREPORT, Context.MODE_PRIVATE)
+                    .edit().clear().commit();
+            // Sanity check...
+            assertEquals("Did not reset properties", STATE_UNKNOWN,
+                    getWarningState(mContext, STATE_UNKNOWN));
+        } else {
+            setWarningState(mContext, propertyState);
+        }
 
         // Send notification and click on share.
         sendBugreportFinished(NO_ID, mPlainTextPath, null);
@@ -510,10 +535,16 @@
 
         // Handle the warning
         mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm));
-        // TODO: get ok and showMessageAgain from the dialog reference above
-        UiObject showMessageAgain =
-                mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_repeat));
-        mUiBot.click(showMessageAgain, "show-message-again");
+        // TODO: get ok and dontShowAgain from the dialog reference above
+        UiObject dontShowAgain =
+                mUiBot.getVisibleObject(mContext.getString(R.string.bugreport_confirm_dont_repeat));
+        final boolean firstTime = propertyState == null || propertyState == STATE_UNKNOWN;
+        if (firstTime) {
+            assertTrue("Checkbox should be checked by default", dontShowAgain.isChecked());
+        } else {
+            assertFalse("Checkbox should not be checked", dontShowAgain.isChecked());
+            mUiBot.click(dontShowAgain, "dont-show-again");
+        }
         UiObject ok = mUiBot.getVisibleObject(mContext.getString(com.android.internal.R.string.ok));
         mUiBot.click(ok, "ok");
 
@@ -523,8 +554,8 @@
         assertActionSendMultiple(extras, BUGREPORT_CONTENT, NO_SCREENSHOT);
 
         // Make sure it's hidden now.
-        int newState = BugreportPrefs.getWarningState(mContext, BugreportPrefs.STATE_UNKNOWN);
-        assertEquals("Didn't change state", BugreportPrefs.STATE_HIDE, newState);
+        int newState = getWarningState(mContext, STATE_UNKNOWN);
+        assertEquals("Didn't change state", STATE_HIDE, newState);
     }
 
     public void testShareBugreportAfterServiceDies() throws Exception {
@@ -876,8 +907,8 @@
     }
 
     private String getPath(String file) {
-        File rootDir = new ContextWrapper(mContext).getFilesDir();
-        File dir = new File(rootDir, BUGREPORTS_DIR);
+        final File rootDir = mContext.getFilesDir();
+        final File dir = new File(rootDir, BUGREPORTS_DIR);
         if (!dir.exists()) {
             Log.i(TAG, "Creating directory " + dir);
             assertTrue("Could not create directory " + dir, dir.mkdir());
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
similarity index 92%
rename from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
index 681ff91..257bf35 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_gain_animation.xml
@@ -18,4 +18,4 @@
     android:propertyName="alpha"
     android:valueTo="1"
     android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
similarity index 92%
rename from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
rename to packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
index e6deb0f..e032008 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_controls_text_focus_lose_animation.xml
@@ -18,4 +18,4 @@
     android:propertyName="alpha"
     android:valueTo="0"
     android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
similarity index 92%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
index 681ff91..257bf35 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_in_animation.xml
@@ -18,4 +18,4 @@
     android:propertyName="alpha"
     android:valueTo="1"
     android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
similarity index 92%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
copy to packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
index e6deb0f..e032008 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_lose_animation.xml
+++ b/packages/SystemUI/res/anim/tv_pip_menu_fade_out_animation.xml
@@ -18,4 +18,4 @@
     android:propertyName="alpha"
     android:valueTo="0"
     android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    android:duration="100" />
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml
new file mode 100644
index 0000000..01c263b
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_button_enter_animation.xml
@@ -0,0 +1,30 @@
+<?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="translationY"
+        android:valueFrom="114dp"
+        android:valueTo="0dp"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+    <objectAnimator
+        android:propertyName="alpha"
+        android:valueTo="1"
+        android:interpolator="@android:interpolator/linear"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml
new file mode 100644
index 0000000..a12b3b6
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_description_enter_animation.xml
@@ -0,0 +1,30 @@
+<?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="translationY"
+        android:valueFrom="84dp"
+        android:valueTo="0dp"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+    <objectAnimator
+        android:propertyName="alpha"
+        android:valueTo="1"
+        android:interpolator="@android:interpolator/linear"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml
new file mode 100644
index 0000000..ae9677e
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_image_enter_animation.xml
@@ -0,0 +1,30 @@
+<?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="translationY"
+        android:valueFrom="114dp"
+        android:valueTo="0dp"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+    <objectAnimator
+        android:propertyName="alpha"
+        android:valueTo="1"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml b/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml
new file mode 100644
index 0000000..4bde070
--- /dev/null
+++ b/packages/SystemUI/res/anim/tv_pip_onboarding_title_enter_animation.xml
@@ -0,0 +1,30 @@
+<?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="translationY"
+        android:valueFrom="84dp"
+        android:valueTo="0dp"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+    <objectAnimator
+        android:propertyName="alpha"
+        android:valueTo="1"
+        android:interpolator="@android:interpolator/fast_out_slow_in"
+        android:duration="@integer/tv_pip_onboarding_anim_duration" />
+</set>
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote.png b/packages/SystemUI/res/drawable-xhdpi/remote.png
new file mode 100644
index 0000000..c0ccfe6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_0.png b/packages/SystemUI/res/drawable-xhdpi/remote_0.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_0.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_1.png b/packages/SystemUI/res/drawable-xhdpi/remote_1.png
new file mode 100644
index 0000000..252ff5e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_1.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_10.png b/packages/SystemUI/res/drawable-xhdpi/remote_10.png
new file mode 100644
index 0000000..5e52b37
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_10.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_100.png b/packages/SystemUI/res/drawable-xhdpi/remote_100.png
new file mode 100644
index 0000000..f604808
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_100.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_101.png b/packages/SystemUI/res/drawable-xhdpi/remote_101.png
new file mode 100644
index 0000000..0272e45
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_101.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_102.png b/packages/SystemUI/res/drawable-xhdpi/remote_102.png
new file mode 100644
index 0000000..aaa35c0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_102.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_103.png b/packages/SystemUI/res/drawable-xhdpi/remote_103.png
new file mode 100644
index 0000000..20f95a5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_103.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_104.png b/packages/SystemUI/res/drawable-xhdpi/remote_104.png
new file mode 100644
index 0000000..052f23e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_104.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_105.png b/packages/SystemUI/res/drawable-xhdpi/remote_105.png
new file mode 100644
index 0000000..c5c8256
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_105.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_106.png b/packages/SystemUI/res/drawable-xhdpi/remote_106.png
new file mode 100644
index 0000000..4e804fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_106.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_107.png b/packages/SystemUI/res/drawable-xhdpi/remote_107.png
new file mode 100644
index 0000000..76669cc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_107.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_108.png b/packages/SystemUI/res/drawable-xhdpi/remote_108.png
new file mode 100644
index 0000000..c1b2f3b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_108.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_109.png b/packages/SystemUI/res/drawable-xhdpi/remote_109.png
new file mode 100644
index 0000000..79e1d7b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_109.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_11.png b/packages/SystemUI/res/drawable-xhdpi/remote_11.png
new file mode 100644
index 0000000..cfec6cb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_11.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_110.png b/packages/SystemUI/res/drawable-xhdpi/remote_110.png
new file mode 100644
index 0000000..d902297
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_110.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_111.png b/packages/SystemUI/res/drawable-xhdpi/remote_111.png
new file mode 100644
index 0000000..e48ed0b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_111.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_112.png b/packages/SystemUI/res/drawable-xhdpi/remote_112.png
new file mode 100644
index 0000000..90dd1a2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_112.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_113.png b/packages/SystemUI/res/drawable-xhdpi/remote_113.png
new file mode 100644
index 0000000..8fb4ad2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_113.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_114.png b/packages/SystemUI/res/drawable-xhdpi/remote_114.png
new file mode 100644
index 0000000..76873fb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_114.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_115.png b/packages/SystemUI/res/drawable-xhdpi/remote_115.png
new file mode 100644
index 0000000..e923d4c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_115.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_116.png b/packages/SystemUI/res/drawable-xhdpi/remote_116.png
new file mode 100644
index 0000000..41d5124
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_116.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_117.png b/packages/SystemUI/res/drawable-xhdpi/remote_117.png
new file mode 100644
index 0000000..eacde64
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_117.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_118.png b/packages/SystemUI/res/drawable-xhdpi/remote_118.png
new file mode 100644
index 0000000..5dc1fb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_118.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_119.png b/packages/SystemUI/res/drawable-xhdpi/remote_119.png
new file mode 100644
index 0000000..a16f037
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_119.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_12.png b/packages/SystemUI/res/drawable-xhdpi/remote_12.png
new file mode 100644
index 0000000..28bb387
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_12.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_120.png b/packages/SystemUI/res/drawable-xhdpi/remote_120.png
new file mode 100644
index 0000000..fe3ef41
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_120.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_121.png b/packages/SystemUI/res/drawable-xhdpi/remote_121.png
new file mode 100644
index 0000000..ef2b892
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_121.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_122.png b/packages/SystemUI/res/drawable-xhdpi/remote_122.png
new file mode 100644
index 0000000..5342976
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_122.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_123.png b/packages/SystemUI/res/drawable-xhdpi/remote_123.png
new file mode 100644
index 0000000..bb8a53a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_123.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_124.png b/packages/SystemUI/res/drawable-xhdpi/remote_124.png
new file mode 100644
index 0000000..b68337e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_124.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_125.png b/packages/SystemUI/res/drawable-xhdpi/remote_125.png
new file mode 100644
index 0000000..81fa3a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_125.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_126.png b/packages/SystemUI/res/drawable-xhdpi/remote_126.png
new file mode 100644
index 0000000..2339d74
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_126.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_127.png b/packages/SystemUI/res/drawable-xhdpi/remote_127.png
new file mode 100644
index 0000000..90d1e0b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_127.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_128.png b/packages/SystemUI/res/drawable-xhdpi/remote_128.png
new file mode 100644
index 0000000..6de4eb8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_128.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_129.png b/packages/SystemUI/res/drawable-xhdpi/remote_129.png
new file mode 100644
index 0000000..9086074
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_129.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_13.png b/packages/SystemUI/res/drawable-xhdpi/remote_13.png
new file mode 100644
index 0000000..a1e212d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_13.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_130.png b/packages/SystemUI/res/drawable-xhdpi/remote_130.png
new file mode 100644
index 0000000..2bc9698
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_130.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_131.png b/packages/SystemUI/res/drawable-xhdpi/remote_131.png
new file mode 100644
index 0000000..d18d2c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_131.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_132.png b/packages/SystemUI/res/drawable-xhdpi/remote_132.png
new file mode 100644
index 0000000..10a00cd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_132.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_133.png b/packages/SystemUI/res/drawable-xhdpi/remote_133.png
new file mode 100644
index 0000000..6f495b4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_133.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_134.png b/packages/SystemUI/res/drawable-xhdpi/remote_134.png
new file mode 100644
index 0000000..703f2c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_134.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_135.png b/packages/SystemUI/res/drawable-xhdpi/remote_135.png
new file mode 100644
index 0000000..f4105b0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_135.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_136.png b/packages/SystemUI/res/drawable-xhdpi/remote_136.png
new file mode 100644
index 0000000..0c3a5bc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_136.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_137.png b/packages/SystemUI/res/drawable-xhdpi/remote_137.png
new file mode 100644
index 0000000..cbebc05
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_137.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_138.png b/packages/SystemUI/res/drawable-xhdpi/remote_138.png
new file mode 100644
index 0000000..6dfefb0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_138.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_139.png b/packages/SystemUI/res/drawable-xhdpi/remote_139.png
new file mode 100644
index 0000000..1acfdd6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_139.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_14.png b/packages/SystemUI/res/drawable-xhdpi/remote_14.png
new file mode 100644
index 0000000..a503cdf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_14.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_140.png b/packages/SystemUI/res/drawable-xhdpi/remote_140.png
new file mode 100644
index 0000000..70d27c1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_140.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_141.png b/packages/SystemUI/res/drawable-xhdpi/remote_141.png
new file mode 100644
index 0000000..d523a0c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_141.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_142.png b/packages/SystemUI/res/drawable-xhdpi/remote_142.png
new file mode 100644
index 0000000..ed6a65d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_142.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_143.png b/packages/SystemUI/res/drawable-xhdpi/remote_143.png
new file mode 100644
index 0000000..9b048e6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_143.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_144.png b/packages/SystemUI/res/drawable-xhdpi/remote_144.png
new file mode 100644
index 0000000..9e2337d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_144.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_145.png b/packages/SystemUI/res/drawable-xhdpi/remote_145.png
new file mode 100644
index 0000000..3f30629
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_145.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_146.png b/packages/SystemUI/res/drawable-xhdpi/remote_146.png
new file mode 100644
index 0000000..1288039
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_146.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_147.png b/packages/SystemUI/res/drawable-xhdpi/remote_147.png
new file mode 100644
index 0000000..d060539
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_147.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_148.png b/packages/SystemUI/res/drawable-xhdpi/remote_148.png
new file mode 100644
index 0000000..5be839d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_148.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_149.png b/packages/SystemUI/res/drawable-xhdpi/remote_149.png
new file mode 100644
index 0000000..39d31ba
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_149.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_15.png b/packages/SystemUI/res/drawable-xhdpi/remote_15.png
new file mode 100644
index 0000000..5695595
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_15.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_150.png b/packages/SystemUI/res/drawable-xhdpi/remote_150.png
new file mode 100644
index 0000000..ec2667c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_150.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_151.png b/packages/SystemUI/res/drawable-xhdpi/remote_151.png
new file mode 100644
index 0000000..ec2667c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_151.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_152.png b/packages/SystemUI/res/drawable-xhdpi/remote_152.png
new file mode 100644
index 0000000..a5d58c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_152.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_153.png b/packages/SystemUI/res/drawable-xhdpi/remote_153.png
new file mode 100644
index 0000000..a5d58c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_153.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_154.png b/packages/SystemUI/res/drawable-xhdpi/remote_154.png
new file mode 100644
index 0000000..a5d58c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_154.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_155.png b/packages/SystemUI/res/drawable-xhdpi/remote_155.png
new file mode 100644
index 0000000..793d411
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_155.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_156.png b/packages/SystemUI/res/drawable-xhdpi/remote_156.png
new file mode 100644
index 0000000..793d411
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_156.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_157.png b/packages/SystemUI/res/drawable-xhdpi/remote_157.png
new file mode 100644
index 0000000..f9d6cdc
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_157.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_158.png b/packages/SystemUI/res/drawable-xhdpi/remote_158.png
new file mode 100644
index 0000000..da8d5d7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_158.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_159.png b/packages/SystemUI/res/drawable-xhdpi/remote_159.png
new file mode 100644
index 0000000..1e0b097
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_159.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_16.png b/packages/SystemUI/res/drawable-xhdpi/remote_16.png
new file mode 100644
index 0000000..4ae106c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_16.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_160.png b/packages/SystemUI/res/drawable-xhdpi/remote_160.png
new file mode 100644
index 0000000..8aa68ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_160.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_161.png b/packages/SystemUI/res/drawable-xhdpi/remote_161.png
new file mode 100644
index 0000000..e49fdd9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_161.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_162.png b/packages/SystemUI/res/drawable-xhdpi/remote_162.png
new file mode 100644
index 0000000..69257a0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_162.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_163.png b/packages/SystemUI/res/drawable-xhdpi/remote_163.png
new file mode 100644
index 0000000..8f0c3d5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_163.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_164.png b/packages/SystemUI/res/drawable-xhdpi/remote_164.png
new file mode 100644
index 0000000..a4c3229
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_164.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_165.png b/packages/SystemUI/res/drawable-xhdpi/remote_165.png
new file mode 100644
index 0000000..46fae23
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_165.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_166.png b/packages/SystemUI/res/drawable-xhdpi/remote_166.png
new file mode 100644
index 0000000..40d5a9b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_166.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_167.png b/packages/SystemUI/res/drawable-xhdpi/remote_167.png
new file mode 100644
index 0000000..6bd0380
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_167.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_168.png b/packages/SystemUI/res/drawable-xhdpi/remote_168.png
new file mode 100644
index 0000000..03904bf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_168.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_169.png b/packages/SystemUI/res/drawable-xhdpi/remote_169.png
new file mode 100644
index 0000000..564a161
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_169.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_17.png b/packages/SystemUI/res/drawable-xhdpi/remote_17.png
new file mode 100644
index 0000000..0703e1a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_17.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_170.png b/packages/SystemUI/res/drawable-xhdpi/remote_170.png
new file mode 100644
index 0000000..0411f94
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_170.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_171.png b/packages/SystemUI/res/drawable-xhdpi/remote_171.png
new file mode 100644
index 0000000..ec141e9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_171.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_172.png b/packages/SystemUI/res/drawable-xhdpi/remote_172.png
new file mode 100644
index 0000000..cb9ecaf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_172.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_173.png b/packages/SystemUI/res/drawable-xhdpi/remote_173.png
new file mode 100644
index 0000000..484ee51
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_173.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_174.png b/packages/SystemUI/res/drawable-xhdpi/remote_174.png
new file mode 100644
index 0000000..85a3135
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_174.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_175.png b/packages/SystemUI/res/drawable-xhdpi/remote_175.png
new file mode 100644
index 0000000..edd6507
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_175.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_176.png b/packages/SystemUI/res/drawable-xhdpi/remote_176.png
new file mode 100644
index 0000000..d95a68b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_176.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_177.png b/packages/SystemUI/res/drawable-xhdpi/remote_177.png
new file mode 100644
index 0000000..305641f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_177.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_178.png b/packages/SystemUI/res/drawable-xhdpi/remote_178.png
new file mode 100644
index 0000000..59de0e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_178.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_179.png b/packages/SystemUI/res/drawable-xhdpi/remote_179.png
new file mode 100644
index 0000000..414e548
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_179.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_18.png b/packages/SystemUI/res/drawable-xhdpi/remote_18.png
new file mode 100644
index 0000000..74df1e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_18.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_180.png b/packages/SystemUI/res/drawable-xhdpi/remote_180.png
new file mode 100644
index 0000000..b5d925c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_180.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_181.png b/packages/SystemUI/res/drawable-xhdpi/remote_181.png
new file mode 100644
index 0000000..e8a7127
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_181.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_182.png b/packages/SystemUI/res/drawable-xhdpi/remote_182.png
new file mode 100644
index 0000000..29c7037
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_182.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_183.png b/packages/SystemUI/res/drawable-xhdpi/remote_183.png
new file mode 100644
index 0000000..9491d94
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_183.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_184.png b/packages/SystemUI/res/drawable-xhdpi/remote_184.png
new file mode 100644
index 0000000..4aa0e32
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_184.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_185.png b/packages/SystemUI/res/drawable-xhdpi/remote_185.png
new file mode 100644
index 0000000..2a0dde8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_185.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_186.png b/packages/SystemUI/res/drawable-xhdpi/remote_186.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_186.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_187.png b/packages/SystemUI/res/drawable-xhdpi/remote_187.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_187.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_188.png b/packages/SystemUI/res/drawable-xhdpi/remote_188.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_188.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_189.png b/packages/SystemUI/res/drawable-xhdpi/remote_189.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_189.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_19.png b/packages/SystemUI/res/drawable-xhdpi/remote_19.png
new file mode 100644
index 0000000..222ea31
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_19.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_190.png b/packages/SystemUI/res/drawable-xhdpi/remote_190.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_190.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_191.png b/packages/SystemUI/res/drawable-xhdpi/remote_191.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_191.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_192.png b/packages/SystemUI/res/drawable-xhdpi/remote_192.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_192.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_193.png b/packages/SystemUI/res/drawable-xhdpi/remote_193.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_193.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_194.png b/packages/SystemUI/res/drawable-xhdpi/remote_194.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_194.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_195.png b/packages/SystemUI/res/drawable-xhdpi/remote_195.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_195.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_196.png b/packages/SystemUI/res/drawable-xhdpi/remote_196.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_196.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_197.png b/packages/SystemUI/res/drawable-xhdpi/remote_197.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_197.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_198.png b/packages/SystemUI/res/drawable-xhdpi/remote_198.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_198.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_199.png b/packages/SystemUI/res/drawable-xhdpi/remote_199.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_199.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_2.png b/packages/SystemUI/res/drawable-xhdpi/remote_2.png
new file mode 100644
index 0000000..fb3f7ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_2.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_20.png b/packages/SystemUI/res/drawable-xhdpi/remote_20.png
new file mode 100644
index 0000000..646587c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_20.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_200.png b/packages/SystemUI/res/drawable-xhdpi/remote_200.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_200.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_201.png b/packages/SystemUI/res/drawable-xhdpi/remote_201.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_201.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_202.png b/packages/SystemUI/res/drawable-xhdpi/remote_202.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_202.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_203.png b/packages/SystemUI/res/drawable-xhdpi/remote_203.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_203.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_204.png b/packages/SystemUI/res/drawable-xhdpi/remote_204.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_204.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_205.png b/packages/SystemUI/res/drawable-xhdpi/remote_205.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_205.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_206.png b/packages/SystemUI/res/drawable-xhdpi/remote_206.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_206.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_207.png b/packages/SystemUI/res/drawable-xhdpi/remote_207.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_207.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_208.png b/packages/SystemUI/res/drawable-xhdpi/remote_208.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_208.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_209.png b/packages/SystemUI/res/drawable-xhdpi/remote_209.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_209.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_21.png b/packages/SystemUI/res/drawable-xhdpi/remote_21.png
new file mode 100644
index 0000000..5858ba92
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_21.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_210.png b/packages/SystemUI/res/drawable-xhdpi/remote_210.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_210.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_211.png b/packages/SystemUI/res/drawable-xhdpi/remote_211.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_211.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_212.png b/packages/SystemUI/res/drawable-xhdpi/remote_212.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_212.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_213.png b/packages/SystemUI/res/drawable-xhdpi/remote_213.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_213.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_214.png b/packages/SystemUI/res/drawable-xhdpi/remote_214.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_214.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_215.png b/packages/SystemUI/res/drawable-xhdpi/remote_215.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_215.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_216.png b/packages/SystemUI/res/drawable-xhdpi/remote_216.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_216.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_217.png b/packages/SystemUI/res/drawable-xhdpi/remote_217.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_217.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_218.png b/packages/SystemUI/res/drawable-xhdpi/remote_218.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_218.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_219.png b/packages/SystemUI/res/drawable-xhdpi/remote_219.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_219.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_22.png b/packages/SystemUI/res/drawable-xhdpi/remote_22.png
new file mode 100644
index 0000000..1974802
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_22.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_220.png b/packages/SystemUI/res/drawable-xhdpi/remote_220.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_220.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_221.png b/packages/SystemUI/res/drawable-xhdpi/remote_221.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_221.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_222.png b/packages/SystemUI/res/drawable-xhdpi/remote_222.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_222.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_223.png b/packages/SystemUI/res/drawable-xhdpi/remote_223.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_223.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_224.png b/packages/SystemUI/res/drawable-xhdpi/remote_224.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_224.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_225.png b/packages/SystemUI/res/drawable-xhdpi/remote_225.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_225.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_226.png b/packages/SystemUI/res/drawable-xhdpi/remote_226.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_226.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_227.png b/packages/SystemUI/res/drawable-xhdpi/remote_227.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_227.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_228.png b/packages/SystemUI/res/drawable-xhdpi/remote_228.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_228.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_229.png b/packages/SystemUI/res/drawable-xhdpi/remote_229.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_229.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_23.png b/packages/SystemUI/res/drawable-xhdpi/remote_23.png
new file mode 100644
index 0000000..96b7c35
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_23.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_230.png b/packages/SystemUI/res/drawable-xhdpi/remote_230.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_230.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_231.png b/packages/SystemUI/res/drawable-xhdpi/remote_231.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_231.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_232.png b/packages/SystemUI/res/drawable-xhdpi/remote_232.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_232.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_233.png b/packages/SystemUI/res/drawable-xhdpi/remote_233.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_233.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_234.png b/packages/SystemUI/res/drawable-xhdpi/remote_234.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_234.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_235.png b/packages/SystemUI/res/drawable-xhdpi/remote_235.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_235.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_236.png b/packages/SystemUI/res/drawable-xhdpi/remote_236.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_236.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_237.png b/packages/SystemUI/res/drawable-xhdpi/remote_237.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_237.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_238.png b/packages/SystemUI/res/drawable-xhdpi/remote_238.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_238.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_239.png b/packages/SystemUI/res/drawable-xhdpi/remote_239.png
new file mode 100644
index 0000000..5bda52e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_239.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_24.png b/packages/SystemUI/res/drawable-xhdpi/remote_24.png
new file mode 100644
index 0000000..0437200
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_24.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_25.png b/packages/SystemUI/res/drawable-xhdpi/remote_25.png
new file mode 100644
index 0000000..60b0f15
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_25.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_26.png b/packages/SystemUI/res/drawable-xhdpi/remote_26.png
new file mode 100644
index 0000000..c34ed97
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_26.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_27.png b/packages/SystemUI/res/drawable-xhdpi/remote_27.png
new file mode 100644
index 0000000..1a83664
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_27.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_28.png b/packages/SystemUI/res/drawable-xhdpi/remote_28.png
new file mode 100644
index 0000000..a3685ad
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_28.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_29.png b/packages/SystemUI/res/drawable-xhdpi/remote_29.png
new file mode 100644
index 0000000..f7135eb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_29.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_3.png b/packages/SystemUI/res/drawable-xhdpi/remote_3.png
new file mode 100644
index 0000000..937da65
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_3.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_30.png b/packages/SystemUI/res/drawable-xhdpi/remote_30.png
new file mode 100644
index 0000000..718cf52
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_30.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_31.png b/packages/SystemUI/res/drawable-xhdpi/remote_31.png
new file mode 100644
index 0000000..c0b55df
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_31.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_32.png b/packages/SystemUI/res/drawable-xhdpi/remote_32.png
new file mode 100644
index 0000000..7a1ce9f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_32.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_33.png b/packages/SystemUI/res/drawable-xhdpi/remote_33.png
new file mode 100644
index 0000000..5428bcf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_33.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_34.png b/packages/SystemUI/res/drawable-xhdpi/remote_34.png
new file mode 100644
index 0000000..264efe8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_34.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_35.png b/packages/SystemUI/res/drawable-xhdpi/remote_35.png
new file mode 100644
index 0000000..a5c450f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_35.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_36.png b/packages/SystemUI/res/drawable-xhdpi/remote_36.png
new file mode 100644
index 0000000..3e469e4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_36.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_37.png b/packages/SystemUI/res/drawable-xhdpi/remote_37.png
new file mode 100644
index 0000000..124ebe4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_37.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_38.png b/packages/SystemUI/res/drawable-xhdpi/remote_38.png
new file mode 100644
index 0000000..b2b4844
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_38.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_39.png b/packages/SystemUI/res/drawable-xhdpi/remote_39.png
new file mode 100644
index 0000000..a6d1733
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_39.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_4.png b/packages/SystemUI/res/drawable-xhdpi/remote_4.png
new file mode 100644
index 0000000..c282f40
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_4.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_40.png b/packages/SystemUI/res/drawable-xhdpi/remote_40.png
new file mode 100644
index 0000000..4cd615c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_40.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_41.png b/packages/SystemUI/res/drawable-xhdpi/remote_41.png
new file mode 100644
index 0000000..c746ae0
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_41.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_42.png b/packages/SystemUI/res/drawable-xhdpi/remote_42.png
new file mode 100644
index 0000000..a93f198
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_42.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_43.png b/packages/SystemUI/res/drawable-xhdpi/remote_43.png
new file mode 100644
index 0000000..966e563
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_43.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_44.png b/packages/SystemUI/res/drawable-xhdpi/remote_44.png
new file mode 100644
index 0000000..beb7031
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_44.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_45.png b/packages/SystemUI/res/drawable-xhdpi/remote_45.png
new file mode 100644
index 0000000..718e167
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_45.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_46.png b/packages/SystemUI/res/drawable-xhdpi/remote_46.png
new file mode 100644
index 0000000..aa54ddb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_46.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_47.png b/packages/SystemUI/res/drawable-xhdpi/remote_47.png
new file mode 100644
index 0000000..1d11270
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_47.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_48.png b/packages/SystemUI/res/drawable-xhdpi/remote_48.png
new file mode 100644
index 0000000..ab31163
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_48.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_49.png b/packages/SystemUI/res/drawable-xhdpi/remote_49.png
new file mode 100644
index 0000000..219b7f6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_49.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_5.png b/packages/SystemUI/res/drawable-xhdpi/remote_5.png
new file mode 100644
index 0000000..15f69e1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_5.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_50.png b/packages/SystemUI/res/drawable-xhdpi/remote_50.png
new file mode 100644
index 0000000..8a9725f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_50.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_51.png b/packages/SystemUI/res/drawable-xhdpi/remote_51.png
new file mode 100644
index 0000000..bc839cf
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_51.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_52.png b/packages/SystemUI/res/drawable-xhdpi/remote_52.png
new file mode 100644
index 0000000..7bab6e5
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_52.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_53.png b/packages/SystemUI/res/drawable-xhdpi/remote_53.png
new file mode 100644
index 0000000..34ab855
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_53.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_54.png b/packages/SystemUI/res/drawable-xhdpi/remote_54.png
new file mode 100644
index 0000000..5bd9f59
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_54.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_55.png b/packages/SystemUI/res/drawable-xhdpi/remote_55.png
new file mode 100644
index 0000000..1ff17f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_55.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_56.png b/packages/SystemUI/res/drawable-xhdpi/remote_56.png
new file mode 100644
index 0000000..d57e067
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_56.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_57.png b/packages/SystemUI/res/drawable-xhdpi/remote_57.png
new file mode 100644
index 0000000..a1bdae1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_57.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_58.png b/packages/SystemUI/res/drawable-xhdpi/remote_58.png
new file mode 100644
index 0000000..c8bc6a4
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_58.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_59.png b/packages/SystemUI/res/drawable-xhdpi/remote_59.png
new file mode 100644
index 0000000..526a24e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_59.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_6.png b/packages/SystemUI/res/drawable-xhdpi/remote_6.png
new file mode 100644
index 0000000..2b6732f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_6.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_60.png b/packages/SystemUI/res/drawable-xhdpi/remote_60.png
new file mode 100644
index 0000000..080619e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_60.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_61.png b/packages/SystemUI/res/drawable-xhdpi/remote_61.png
new file mode 100644
index 0000000..5932a8c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_61.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_62.png b/packages/SystemUI/res/drawable-xhdpi/remote_62.png
new file mode 100644
index 0000000..d1233dd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_62.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_63.png b/packages/SystemUI/res/drawable-xhdpi/remote_63.png
new file mode 100644
index 0000000..4f230c7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_63.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_64.png b/packages/SystemUI/res/drawable-xhdpi/remote_64.png
new file mode 100644
index 0000000..6b89fcb
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_64.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_65.png b/packages/SystemUI/res/drawable-xhdpi/remote_65.png
new file mode 100644
index 0000000..87597b1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_65.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_66.png b/packages/SystemUI/res/drawable-xhdpi/remote_66.png
new file mode 100644
index 0000000..0ee8c1e
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_66.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_67.png b/packages/SystemUI/res/drawable-xhdpi/remote_67.png
new file mode 100644
index 0000000..9aca8fd
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_67.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_68.png b/packages/SystemUI/res/drawable-xhdpi/remote_68.png
new file mode 100644
index 0000000..5f263ae
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_68.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_69.png b/packages/SystemUI/res/drawable-xhdpi/remote_69.png
new file mode 100644
index 0000000..1a22b61
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_69.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_7.png b/packages/SystemUI/res/drawable-xhdpi/remote_7.png
new file mode 100644
index 0000000..9d9d699
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_7.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_70.png b/packages/SystemUI/res/drawable-xhdpi/remote_70.png
new file mode 100644
index 0000000..0372c50
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_70.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_71.png b/packages/SystemUI/res/drawable-xhdpi/remote_71.png
new file mode 100644
index 0000000..854e3e2
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_71.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_72.png b/packages/SystemUI/res/drawable-xhdpi/remote_72.png
new file mode 100644
index 0000000..6919624
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_72.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_73.png b/packages/SystemUI/res/drawable-xhdpi/remote_73.png
new file mode 100644
index 0000000..d8e9ae1
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_73.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_74.png b/packages/SystemUI/res/drawable-xhdpi/remote_74.png
new file mode 100644
index 0000000..24e5b6a
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_74.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_75.png b/packages/SystemUI/res/drawable-xhdpi/remote_75.png
new file mode 100644
index 0000000..369a3a9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_75.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_76.png b/packages/SystemUI/res/drawable-xhdpi/remote_76.png
new file mode 100644
index 0000000..96824c6
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_76.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_77.png b/packages/SystemUI/res/drawable-xhdpi/remote_77.png
new file mode 100644
index 0000000..dd60cca
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_77.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_78.png b/packages/SystemUI/res/drawable-xhdpi/remote_78.png
new file mode 100644
index 0000000..aa3460b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_78.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_79.png b/packages/SystemUI/res/drawable-xhdpi/remote_79.png
new file mode 100644
index 0000000..9a60e3c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_79.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_8.png b/packages/SystemUI/res/drawable-xhdpi/remote_8.png
new file mode 100644
index 0000000..b73c7ef
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_8.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_80.png b/packages/SystemUI/res/drawable-xhdpi/remote_80.png
new file mode 100644
index 0000000..cbf883c
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_80.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_81.png b/packages/SystemUI/res/drawable-xhdpi/remote_81.png
new file mode 100644
index 0000000..11a6add
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_81.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_82.png b/packages/SystemUI/res/drawable-xhdpi/remote_82.png
new file mode 100644
index 0000000..e05105d
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_82.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_83.png b/packages/SystemUI/res/drawable-xhdpi/remote_83.png
new file mode 100644
index 0000000..57813aa
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_83.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_84.png b/packages/SystemUI/res/drawable-xhdpi/remote_84.png
new file mode 100644
index 0000000..0f6f0fe
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_84.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_85.png b/packages/SystemUI/res/drawable-xhdpi/remote_85.png
new file mode 100644
index 0000000..ada83ec
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_85.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_86.png b/packages/SystemUI/res/drawable-xhdpi/remote_86.png
new file mode 100644
index 0000000..442dd51
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_86.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_87.png b/packages/SystemUI/res/drawable-xhdpi/remote_87.png
new file mode 100644
index 0000000..bdb4962
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_87.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_88.png b/packages/SystemUI/res/drawable-xhdpi/remote_88.png
new file mode 100644
index 0000000..b318002
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_88.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_89.png b/packages/SystemUI/res/drawable-xhdpi/remote_89.png
new file mode 100644
index 0000000..c4ed874
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_89.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_9.png b/packages/SystemUI/res/drawable-xhdpi/remote_9.png
new file mode 100644
index 0000000..ce5041f
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_90.png b/packages/SystemUI/res/drawable-xhdpi/remote_90.png
new file mode 100644
index 0000000..6a662f9
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_90.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_91.png b/packages/SystemUI/res/drawable-xhdpi/remote_91.png
new file mode 100644
index 0000000..21be887
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_91.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_92.png b/packages/SystemUI/res/drawable-xhdpi/remote_92.png
new file mode 100644
index 0000000..1bc5361
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_92.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_93.png b/packages/SystemUI/res/drawable-xhdpi/remote_93.png
new file mode 100644
index 0000000..76495ac
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_93.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_94.png b/packages/SystemUI/res/drawable-xhdpi/remote_94.png
new file mode 100644
index 0000000..081c84b
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_94.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_95.png b/packages/SystemUI/res/drawable-xhdpi/remote_95.png
new file mode 100644
index 0000000..e9c27a8
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_95.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_96.png b/packages/SystemUI/res/drawable-xhdpi/remote_96.png
new file mode 100644
index 0000000..1369603
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_96.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_97.png b/packages/SystemUI/res/drawable-xhdpi/remote_97.png
new file mode 100644
index 0000000..fbd1458
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_97.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_98.png b/packages/SystemUI/res/drawable-xhdpi/remote_98.png
new file mode 100644
index 0000000..ccdd7a7
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_98.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/remote_99.png b/packages/SystemUI/res/drawable-xhdpi/remote_99.png
new file mode 100644
index 0000000..f3cb4db
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/remote_99.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
index e98d43f..1e52a91 100644
--- a/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
+++ b/packages/SystemUI/res/drawable/recents_tv_background_gradient.xml
@@ -16,7 +16,7 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
     <gradient
-            android:startColor="#99000000"
-            android:endColor="#E6000000"
+            android:startColor="#4C000000"
+            android:endColor="#72000000"
             android:angle="90"/>
 </shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
index 405ea0c..0db1a57 100644
--- a/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_button_focused.xml
@@ -14,11 +14,5 @@
      limitations under the License.
 -->
 
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="oval">
-    <size
-        android:width="34dp"
-        android:height="34dp" />
-    <solid
-        android:color="#4DFFFFFF" />
-</shape>
+<ripple xmlns:android="http://schemas.android.com/apk/res/android"
+    android:color="#9AFFFFFF" android:radius="17dp" />
diff --git a/packages/SystemUI/res/drawable/tv_pip_close_button.xml b/packages/SystemUI/res/drawable/tv_pip_close_button.xml
deleted file mode 100644
index 186a4ba..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_close_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:constantSize="true">
-    <item android:state_focused="true">
-        <layer-list>
-            <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_close_white"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-    <item>
-        <layer-list>
-            <item android:drawable="@drawable/ic_close_white"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_full_button.xml b/packages/SystemUI/res/drawable/tv_pip_full_button.xml
deleted file mode 100644
index c48dc828..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_full_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:constantSize="true">
-    <item android:state_focused="true">
-        <layer-list>
-            <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_fullscreen_white_24dp"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-    <item>
-        <layer-list>
-            <item android:drawable="@drawable/ic_fullscreen_white_24dp"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml b/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml
new file mode 100644
index 0000000..d46108a
--- /dev/null
+++ b/packages/SystemUI/res/drawable/tv_pip_onboarding_remote.xml
@@ -0,0 +1,259 @@
+<?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.
+-->
+<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
+    android:oneshot="false">
+
+    <item android:drawable="@drawable/remote_0" android:duration="13" />
+    <item android:drawable="@drawable/remote_1" android:duration="13" />
+    <item android:drawable="@drawable/remote_2" android:duration="13" />
+    <item android:drawable="@drawable/remote_3" android:duration="13" />
+    <item android:drawable="@drawable/remote_4" android:duration="13" />
+    <item android:drawable="@drawable/remote_5" android:duration="13" />
+    <item android:drawable="@drawable/remote_6" android:duration="13" />
+    <item android:drawable="@drawable/remote_7" android:duration="13" />
+    <item android:drawable="@drawable/remote_8" android:duration="13" />
+    <item android:drawable="@drawable/remote_9" android:duration="13" />
+    <item android:drawable="@drawable/remote_10" android:duration="13" />
+    <item android:drawable="@drawable/remote_11" android:duration="13" />
+    <item android:drawable="@drawable/remote_12" android:duration="13" />
+    <item android:drawable="@drawable/remote_13" android:duration="13" />
+    <item android:drawable="@drawable/remote_14" android:duration="13" />
+    <item android:drawable="@drawable/remote_15" android:duration="13" />
+    <item android:drawable="@drawable/remote_16" android:duration="13" />
+    <item android:drawable="@drawable/remote_17" android:duration="13" />
+    <item android:drawable="@drawable/remote_18" android:duration="13" />
+    <item android:drawable="@drawable/remote_19" android:duration="13" />
+    <item android:drawable="@drawable/remote_20" android:duration="13" />
+    <item android:drawable="@drawable/remote_21" android:duration="13" />
+    <item android:drawable="@drawable/remote_22" android:duration="13" />
+    <item android:drawable="@drawable/remote_23" android:duration="13" />
+    <item android:drawable="@drawable/remote_24" android:duration="13" />
+    <item android:drawable="@drawable/remote_25" android:duration="13" />
+    <item android:drawable="@drawable/remote_26" android:duration="13" />
+    <item android:drawable="@drawable/remote_27" android:duration="13" />
+    <item android:drawable="@drawable/remote_28" android:duration="13" />
+    <item android:drawable="@drawable/remote_29" android:duration="13" />
+    <item android:drawable="@drawable/remote_30" android:duration="13" />
+    <item android:drawable="@drawable/remote_31" android:duration="13" />
+    <item android:drawable="@drawable/remote_32" android:duration="13" />
+    <item android:drawable="@drawable/remote_33" android:duration="13" />
+    <item android:drawable="@drawable/remote_34" android:duration="13" />
+    <item android:drawable="@drawable/remote_35" android:duration="13" />
+    <item android:drawable="@drawable/remote_36" android:duration="13" />
+    <item android:drawable="@drawable/remote_37" android:duration="13" />
+    <item android:drawable="@drawable/remote_38" android:duration="13" />
+    <item android:drawable="@drawable/remote_39" android:duration="13" />
+    <item android:drawable="@drawable/remote_40" android:duration="13" />
+    <item android:drawable="@drawable/remote_41" android:duration="13" />
+    <item android:drawable="@drawable/remote_42" android:duration="13" />
+    <item android:drawable="@drawable/remote_43" android:duration="13" />
+    <item android:drawable="@drawable/remote_44" android:duration="13" />
+    <item android:drawable="@drawable/remote_45" android:duration="13" />
+    <item android:drawable="@drawable/remote_46" android:duration="13" />
+    <item android:drawable="@drawable/remote_47" android:duration="13" />
+    <item android:drawable="@drawable/remote_48" android:duration="13" />
+    <item android:drawable="@drawable/remote_49" android:duration="13" />
+    <item android:drawable="@drawable/remote_50" android:duration="13" />
+    <item android:drawable="@drawable/remote_51" android:duration="13" />
+    <item android:drawable="@drawable/remote_52" android:duration="13" />
+    <item android:drawable="@drawable/remote_53" android:duration="13" />
+    <item android:drawable="@drawable/remote_54" android:duration="13" />
+    <item android:drawable="@drawable/remote_55" android:duration="13" />
+    <item android:drawable="@drawable/remote_56" android:duration="13" />
+    <item android:drawable="@drawable/remote_57" android:duration="13" />
+    <item android:drawable="@drawable/remote_58" android:duration="13" />
+    <item android:drawable="@drawable/remote_59" android:duration="13" />
+    <item android:drawable="@drawable/remote_60" android:duration="13" />
+    <item android:drawable="@drawable/remote_61" android:duration="13" />
+    <item android:drawable="@drawable/remote_62" android:duration="13" />
+    <item android:drawable="@drawable/remote_63" android:duration="13" />
+    <item android:drawable="@drawable/remote_64" android:duration="13" />
+    <item android:drawable="@drawable/remote_65" android:duration="13" />
+    <item android:drawable="@drawable/remote_66" android:duration="13" />
+    <item android:drawable="@drawable/remote_67" android:duration="13" />
+    <item android:drawable="@drawable/remote_68" android:duration="13" />
+    <item android:drawable="@drawable/remote_69" android:duration="13" />
+    <item android:drawable="@drawable/remote_70" android:duration="13" />
+    <item android:drawable="@drawable/remote_71" android:duration="13" />
+    <item android:drawable="@drawable/remote_72" android:duration="13" />
+    <item android:drawable="@drawable/remote_73" android:duration="13" />
+    <item android:drawable="@drawable/remote_74" android:duration="13" />
+    <item android:drawable="@drawable/remote_75" android:duration="13" />
+    <item android:drawable="@drawable/remote_76" android:duration="13" />
+    <item android:drawable="@drawable/remote_77" android:duration="13" />
+    <item android:drawable="@drawable/remote_78" android:duration="13" />
+    <item android:drawable="@drawable/remote_79" android:duration="13" />
+    <item android:drawable="@drawable/remote_80" android:duration="13" />
+    <item android:drawable="@drawable/remote_81" android:duration="13" />
+    <item android:drawable="@drawable/remote_82" android:duration="13" />
+    <item android:drawable="@drawable/remote_83" android:duration="13" />
+    <item android:drawable="@drawable/remote_84" android:duration="13" />
+    <item android:drawable="@drawable/remote_85" android:duration="13" />
+    <item android:drawable="@drawable/remote_86" android:duration="13" />
+    <item android:drawable="@drawable/remote_87" android:duration="13" />
+    <item android:drawable="@drawable/remote_88" android:duration="13" />
+    <item android:drawable="@drawable/remote_89" android:duration="13" />
+    <item android:drawable="@drawable/remote_90" android:duration="13" />
+    <item android:drawable="@drawable/remote_91" android:duration="13" />
+    <item android:drawable="@drawable/remote_92" android:duration="13" />
+    <item android:drawable="@drawable/remote_93" android:duration="13" />
+    <item android:drawable="@drawable/remote_94" android:duration="13" />
+    <item android:drawable="@drawable/remote_95" android:duration="13" />
+    <item android:drawable="@drawable/remote_96" android:duration="13" />
+    <item android:drawable="@drawable/remote_97" android:duration="13" />
+    <item android:drawable="@drawable/remote_98" android:duration="13" />
+    <item android:drawable="@drawable/remote_99" android:duration="13" />
+    <item android:drawable="@drawable/remote_100" android:duration="13" />
+    <item android:drawable="@drawable/remote_101" android:duration="13" />
+    <item android:drawable="@drawable/remote_102" android:duration="13" />
+    <item android:drawable="@drawable/remote_103" android:duration="13" />
+    <item android:drawable="@drawable/remote_104" android:duration="13" />
+    <item android:drawable="@drawable/remote_105" android:duration="13" />
+    <item android:drawable="@drawable/remote_106" android:duration="13" />
+    <item android:drawable="@drawable/remote_107" android:duration="13" />
+    <item android:drawable="@drawable/remote_108" android:duration="13" />
+    <item android:drawable="@drawable/remote_109" android:duration="13" />
+    <item android:drawable="@drawable/remote_110" android:duration="13" />
+    <item android:drawable="@drawable/remote_111" android:duration="13" />
+    <item android:drawable="@drawable/remote_112" android:duration="13" />
+    <item android:drawable="@drawable/remote_113" android:duration="13" />
+    <item android:drawable="@drawable/remote_114" android:duration="13" />
+    <item android:drawable="@drawable/remote_115" android:duration="13" />
+    <item android:drawable="@drawable/remote_116" android:duration="13" />
+    <item android:drawable="@drawable/remote_117" android:duration="13" />
+    <item android:drawable="@drawable/remote_118" android:duration="13" />
+    <item android:drawable="@drawable/remote_119" android:duration="13" />
+    <item android:drawable="@drawable/remote_120" android:duration="13" />
+    <item android:drawable="@drawable/remote_121" android:duration="13" />
+    <item android:drawable="@drawable/remote_122" android:duration="13" />
+    <item android:drawable="@drawable/remote_123" android:duration="13" />
+    <item android:drawable="@drawable/remote_124" android:duration="13" />
+    <item android:drawable="@drawable/remote_125" android:duration="13" />
+    <item android:drawable="@drawable/remote_126" android:duration="13" />
+    <item android:drawable="@drawable/remote_127" android:duration="13" />
+    <item android:drawable="@drawable/remote_128" android:duration="13" />
+    <item android:drawable="@drawable/remote_129" android:duration="13" />
+    <item android:drawable="@drawable/remote_130" android:duration="13" />
+    <item android:drawable="@drawable/remote_131" android:duration="13" />
+    <item android:drawable="@drawable/remote_132" android:duration="13" />
+    <item android:drawable="@drawable/remote_133" android:duration="13" />
+    <item android:drawable="@drawable/remote_134" android:duration="13" />
+    <item android:drawable="@drawable/remote_135" android:duration="13" />
+    <item android:drawable="@drawable/remote_136" android:duration="13" />
+    <item android:drawable="@drawable/remote_137" android:duration="13" />
+    <item android:drawable="@drawable/remote_138" android:duration="13" />
+    <item android:drawable="@drawable/remote_139" android:duration="13" />
+    <item android:drawable="@drawable/remote_140" android:duration="13" />
+    <item android:drawable="@drawable/remote_141" android:duration="13" />
+    <item android:drawable="@drawable/remote_142" android:duration="13" />
+    <item android:drawable="@drawable/remote_143" android:duration="13" />
+    <item android:drawable="@drawable/remote_144" android:duration="13" />
+    <item android:drawable="@drawable/remote_145" android:duration="13" />
+    <item android:drawable="@drawable/remote_146" android:duration="13" />
+    <item android:drawable="@drawable/remote_147" android:duration="13" />
+    <item android:drawable="@drawable/remote_148" android:duration="13" />
+    <item android:drawable="@drawable/remote_149" android:duration="13" />
+    <item android:drawable="@drawable/remote_150" android:duration="13" />
+    <item android:drawable="@drawable/remote_151" android:duration="13" />
+    <item android:drawable="@drawable/remote_152" android:duration="13" />
+    <item android:drawable="@drawable/remote_153" android:duration="13" />
+    <item android:drawable="@drawable/remote_154" android:duration="13" />
+    <item android:drawable="@drawable/remote_155" android:duration="13" />
+    <item android:drawable="@drawable/remote_156" android:duration="13" />
+    <item android:drawable="@drawable/remote_157" android:duration="13" />
+    <item android:drawable="@drawable/remote_158" android:duration="13" />
+    <item android:drawable="@drawable/remote_159" android:duration="13" />
+    <item android:drawable="@drawable/remote_160" android:duration="13" />
+    <item android:drawable="@drawable/remote_161" android:duration="13" />
+    <item android:drawable="@drawable/remote_162" android:duration="13" />
+    <item android:drawable="@drawable/remote_163" android:duration="13" />
+    <item android:drawable="@drawable/remote_164" android:duration="13" />
+    <item android:drawable="@drawable/remote_165" android:duration="13" />
+    <item android:drawable="@drawable/remote_166" android:duration="13" />
+    <item android:drawable="@drawable/remote_167" android:duration="13" />
+    <item android:drawable="@drawable/remote_168" android:duration="13" />
+    <item android:drawable="@drawable/remote_169" android:duration="13" />
+    <item android:drawable="@drawable/remote_170" android:duration="13" />
+    <item android:drawable="@drawable/remote_171" android:duration="13" />
+    <item android:drawable="@drawable/remote_172" android:duration="13" />
+    <item android:drawable="@drawable/remote_173" android:duration="13" />
+    <item android:drawable="@drawable/remote_174" android:duration="13" />
+    <item android:drawable="@drawable/remote_175" android:duration="13" />
+    <item android:drawable="@drawable/remote_176" android:duration="13" />
+    <item android:drawable="@drawable/remote_177" android:duration="13" />
+    <item android:drawable="@drawable/remote_178" android:duration="13" />
+    <item android:drawable="@drawable/remote_179" android:duration="13" />
+    <item android:drawable="@drawable/remote_180" android:duration="13" />
+    <item android:drawable="@drawable/remote_181" android:duration="13" />
+    <item android:drawable="@drawable/remote_182" android:duration="13" />
+    <item android:drawable="@drawable/remote_183" android:duration="13" />
+    <item android:drawable="@drawable/remote_184" android:duration="13" />
+    <item android:drawable="@drawable/remote_185" android:duration="13" />
+    <item android:drawable="@drawable/remote_186" android:duration="13" />
+    <item android:drawable="@drawable/remote_187" android:duration="13" />
+    <item android:drawable="@drawable/remote_188" android:duration="13" />
+    <item android:drawable="@drawable/remote_189" android:duration="13" />
+    <item android:drawable="@drawable/remote_190" android:duration="13" />
+    <item android:drawable="@drawable/remote_191" android:duration="13" />
+    <item android:drawable="@drawable/remote_192" android:duration="13" />
+    <item android:drawable="@drawable/remote_193" android:duration="13" />
+    <item android:drawable="@drawable/remote_194" android:duration="13" />
+    <item android:drawable="@drawable/remote_195" android:duration="13" />
+    <item android:drawable="@drawable/remote_196" android:duration="13" />
+    <item android:drawable="@drawable/remote_197" android:duration="13" />
+    <item android:drawable="@drawable/remote_198" android:duration="13" />
+    <item android:drawable="@drawable/remote_199" android:duration="13" />
+    <item android:drawable="@drawable/remote_200" android:duration="13" />
+    <item android:drawable="@drawable/remote_201" android:duration="13" />
+    <item android:drawable="@drawable/remote_202" android:duration="13" />
+    <item android:drawable="@drawable/remote_203" android:duration="13" />
+    <item android:drawable="@drawable/remote_204" android:duration="13" />
+    <item android:drawable="@drawable/remote_205" android:duration="13" />
+    <item android:drawable="@drawable/remote_206" android:duration="13" />
+    <item android:drawable="@drawable/remote_207" android:duration="13" />
+    <item android:drawable="@drawable/remote_208" android:duration="13" />
+    <item android:drawable="@drawable/remote_209" android:duration="13" />
+    <item android:drawable="@drawable/remote_210" android:duration="13" />
+    <item android:drawable="@drawable/remote_211" android:duration="13" />
+    <item android:drawable="@drawable/remote_212" android:duration="13" />
+    <item android:drawable="@drawable/remote_213" android:duration="13" />
+    <item android:drawable="@drawable/remote_214" android:duration="13" />
+    <item android:drawable="@drawable/remote_215" android:duration="13" />
+    <item android:drawable="@drawable/remote_216" android:duration="13" />
+    <item android:drawable="@drawable/remote_217" android:duration="13" />
+    <item android:drawable="@drawable/remote_218" android:duration="13" />
+    <item android:drawable="@drawable/remote_219" android:duration="13" />
+    <item android:drawable="@drawable/remote_220" android:duration="13" />
+    <item android:drawable="@drawable/remote_221" android:duration="13" />
+    <item android:drawable="@drawable/remote_222" android:duration="13" />
+    <item android:drawable="@drawable/remote_223" android:duration="13" />
+    <item android:drawable="@drawable/remote_224" android:duration="13" />
+    <item android:drawable="@drawable/remote_225" android:duration="13" />
+    <item android:drawable="@drawable/remote_226" android:duration="13" />
+    <item android:drawable="@drawable/remote_227" android:duration="13" />
+    <item android:drawable="@drawable/remote_228" android:duration="13" />
+    <item android:drawable="@drawable/remote_229" android:duration="13" />
+    <item android:drawable="@drawable/remote_230" android:duration="13" />
+    <item android:drawable="@drawable/remote_231" android:duration="13" />
+    <item android:drawable="@drawable/remote_232" android:duration="13" />
+    <item android:drawable="@drawable/remote_233" android:duration="13" />
+    <item android:drawable="@drawable/remote_234" android:duration="13" />
+    <item android:drawable="@drawable/remote_235" android:duration="13" />
+    <item android:drawable="@drawable/remote_236" android:duration="13" />
+    <item android:drawable="@drawable/remote_237" android:duration="13" />
+    <item android:drawable="@drawable/remote_238" android:duration="13" />
+    <item android:drawable="@drawable/remote_239" android:duration="13" />
+</animation-list>
diff --git a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
index e247dec..2b58fc5 100644
--- a/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_background.xml
@@ -16,8 +16,5 @@
 <shape xmlns:android="http://schemas.android.com/apk/res/android"
     android:shape="rectangle">
 
-    <gradient
-        android:startColor="#B2000000"
-        android:endColor="#00000000"
-        android:angle="90"/>
+    <stroke android:width="1dp" android:color="#33FFFFFF" />
 </shape>
diff --git a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
similarity index 61%
copy from packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
copy to packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
index 681ff91..e247dec 100644
--- a/packages/SystemUI/res/anim/tv_pip_controls_text_in_recents_focus_gain_animation.xml
+++ b/packages/SystemUI/res/drawable/tv_pip_overlay_text_background.xml
@@ -1,5 +1,5 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
+<!--
+     Copyright (C) 2016 The Android Open Source Project
 
      Licensed under the Apache License, Version 2.0 (the "License");
      you may not use this file except in compliance with the License.
@@ -13,9 +13,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="rectangle">
 
-<objectAnimator xmlns:android="http://schemas.android.com/apk/res/android"
-    android:propertyName="alpha"
-    android:valueTo="1"
-    android:interpolator="@android:interpolator/fast_out_slow_in"
-    android:duration="@integer/recents_tv_pip_focus_anim_duration" />
+    <gradient
+        android:startColor="#B2000000"
+        android:endColor="#00000000"
+        android:angle="90"/>
+</shape>
diff --git a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml b/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
deleted file mode 100644
index bcc8973..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_pause_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:constantSize="true">
-    <item android:state_focused="true">
-        <layer-list>
-            <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_pause_white_24dp"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-    <item>
-        <layer-list>
-            <item android:drawable="@drawable/ic_pause_white_24dp"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-</selector>
diff --git a/packages/SystemUI/res/drawable/tv_pip_play_button.xml b/packages/SystemUI/res/drawable/tv_pip_play_button.xml
deleted file mode 100644
index f77ea1d..0000000
--- a/packages/SystemUI/res/drawable/tv_pip_play_button.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2016 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<selector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:constantSize="true">
-    <item android:state_focused="true">
-        <layer-list>
-            <item android:drawable="@drawable/tv_pip_button_focused" />
-            <item android:drawable="@drawable/ic_play_arrow_white_24dp"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-    <item>
-        <layer-list>
-            <item android:drawable="@drawable/ic_play_arrow_white_24dp"
-                android:top="@dimen/tv_pip_button_icon_padding"
-                android:bottom="@dimen/tv_pip_button_icon_padding"
-                android:left="@dimen/tv_pip_button_icon_padding"
-                android:right="@dimen/tv_pip_button_icon_padding" />
-        </layer-list>
-    </item>
-</selector>
diff --git a/packages/SystemUI/res/layout/recents_on_tv.xml b/packages/SystemUI/res/layout-television/recents_on_tv.xml
similarity index 88%
rename from packages/SystemUI/res/layout/recents_on_tv.xml
rename to packages/SystemUI/res/layout-television/recents_on_tv.xml
index 28ea66d..1dbd1b3 100644
--- a/packages/SystemUI/res/layout/recents_on_tv.xml
+++ b/packages/SystemUI/res/layout-television/recents_on_tv.xml
@@ -19,7 +19,8 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:clipChildren="false"
-    android:clipToPadding="false">
+    android:clipToPadding="false"
+    android:background="@drawable/recents_tv_background_gradient">
     <com.android.systemui.recents.tv.views.TaskStackHorizontalGridView
         android:id="@+id/task_list"
         android:layout_width="wrap_content"
@@ -34,9 +35,9 @@
     <!-- Placeholder view to give focus to the PIP menus. -->
     <View
         android:id="@+id/pip"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
+        android:layout_width="1dp"
+        android:layout_height="1dp"
         android:focusable="true"
-        android:visibility="gone" />
+        android:visibility="visible" />
 
 </com.android.systemui.recents.tv.views.RecentsTvView>
diff --git a/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml b/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml
new file mode 100644
index 0000000..186a058
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_card_dismiss.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:id="@+id/card_dismiss"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:orientation="vertical"
+        android:layout_gravity="center_horizontal"
+        android:alpha="0.0"
+        tools:showIn="@layout/recents_tv_task_card_view">
+    <ImageView
+            android:id="@+id/card_dismiss_icon"
+            android:layout_width="@dimen/recents_tv_dismiss_icon_size"
+            android:layout_height="@dimen/recents_tv_dismiss_icon_size"
+            android:layout_gravity="center_horizontal"
+            android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
+            android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
+            android:src="@drawable/ic_cancel_white_24dp"/>
+    <TextView
+            android:id="@+id/card_dismiss_text"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textSize="@dimen/recents_tv_dismiss_text_size"
+            android:fontFamily="@string/font_roboto_light"
+            android:textColor="@color/recents_tv_dismiss_text_color"
+            android:text="@string/recents_tv_dismiss"
+            android:layout_gravity="center_horizontal"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml b/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml
new file mode 100644
index 0000000..20397c3
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_card_info_field.xml
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2016 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+<LinearLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        xmlns:tools="http://schemas.android.com/tools"
+        android:id="@+id/card_info_field"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        tools:showIn="@layout/recents_tv_task_card_view_fallback_banner">
+    <ImageView
+            android:id="@+id/card_extra_badge"
+            android:layout_width="@dimen/recents_tv_card_extra_badge_size"
+            android:layout_height="@dimen/recents_tv_card_extra_badge_size"
+            android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
+            android:scaleType="fitCenter"
+            android:layout_centerVertical="true"
+            android:layout_alignParentEnd="true"/>
+    <TextView
+            android:id="@+id/card_title_text"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:includeFontPadding="true"
+            android:singleLine="true"
+            android:shadowColor="@color/recents_tv_text_shadow_color"
+            android:shadowRadius="5"
+            android:shadowDx="0"
+            android:shadowDy="0"
+            android:textColor="@color/recents_tv_card_title_text_color"
+            android:fontFamily="@string/font_roboto_regular"
+            android:textSize="@dimen/recents_tv_title_text_size"
+            android:paddingStart="@dimen/recents_tv_text_padding_start"
+            android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
+            android:ellipsize="end"/>
+</LinearLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
new file mode 100644
index 0000000..9b89aa0
--- /dev/null
+++ b/packages/SystemUI/res/layout-television/recents_tv_task_card_view.xml
@@ -0,0 +1,46 @@
+<?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.
+-->
+<com.android.systemui.recents.tv.views.TaskCardView
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:focusable="true"
+        android:focusableInTouchMode="true"
+        android:layout_gravity="center"
+        android:layout_centerInParent="true"
+        android:clipToPadding="false"
+        android:orientation="vertical" >
+    <include layout="@layout/recents_tv_card_info_field"/>
+    <LinearLayout
+            android:id="@+id/card_view_thumbnail"
+            android:layout_width="@dimen/recents_tv_card_width"
+            android:layout_height="@dimen/recents_tv_screenshot_height"
+            android:gravity="center"
+            android:orientation="vertical"
+            android:background="@color/recents_tv_card_background_color"
+            android:layout_centerHorizontal="true" >
+
+        <ImageView
+                android:id="@+id/card_view_banner_icon"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:layout_centerHorizontal="true"
+                android:scaleType="centerCrop"
+                android:gravity="center" />
+
+    </LinearLayout>
+    <include layout="@layout/recents_tv_card_dismiss"/>
+</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
index 9dd3ad2..55d7fab 100644
--- a/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
+++ b/packages/SystemUI/res/layout/qs_paged_tile_layout.xml
@@ -33,7 +33,9 @@
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:layout_gravity="center"
-            android:gravity="center" />
+            android:gravity="center"
+            android:importantForAccessibility="yes"
+            android:focusable="true" />
 
         <TextView
             android:id="@android:id/edit"
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index b1b2f1e..1978a93 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -18,47 +18,43 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:focusable="true">
-    <FrameLayout
-        android:id="@+id/task_view_content"
+    <com.android.systemui.recents.views.TaskViewThumbnail
+        android:id="@+id/task_view_thumbnail"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
-        <com.android.systemui.recents.views.TaskViewThumbnail
-            android:id="@+id/task_view_thumbnail"
-            android:layout_width="match_parent"
-            android:layout_height="match_parent" />
+        android:layout_height="match_parent" />
 
-        <include layout="@layout/recents_task_view_header" />
+    <include layout="@layout/recents_task_view_header" />
 
-        <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
-            android:id="@+id/lock_to_app_fab"
-            android:layout_width="@dimen/recents_lock_to_app_size"
-            android:layout_height="@dimen/recents_lock_to_app_size"
-            android:layout_gravity="bottom|right"
-            android:layout_marginRight="15dp"
-            android:layout_marginBottom="15dp"
-            android:translationZ="4dp"
-            android:contentDescription="@string/recents_lock_to_app_button_label"
-            android:background="@drawable/recents_lock_to_task_button_bg"
-            android:visibility="invisible"
-            android:alpha="0">
-            <ImageView
-                android:layout_width="@dimen/recents_lock_to_app_icon_size"
-                android:layout_height="@dimen/recents_lock_to_app_icon_size"
-                android:layout_gravity="center"
-                android:src="@drawable/recents_lock_to_app_pin" />
-        </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
+    <!-- TODO: Move this into a view stub -->
+    <com.android.systemui.statusbar.AlphaOptimizedFrameLayout
+        android:id="@+id/lock_to_app_fab"
+        android:layout_width="@dimen/recents_lock_to_app_size"
+        android:layout_height="@dimen/recents_lock_to_app_size"
+        android:layout_gravity="bottom|right"
+        android:layout_marginRight="15dp"
+        android:layout_marginBottom="15dp"
+        android:translationZ="4dp"
+        android:contentDescription="@string/recents_lock_to_app_button_label"
+        android:background="@drawable/recents_lock_to_task_button_bg"
+        android:visibility="invisible"
+        android:alpha="0">
+        <ImageView
+            android:layout_width="@dimen/recents_lock_to_app_icon_size"
+            android:layout_height="@dimen/recents_lock_to_app_icon_size"
+            android:layout_gravity="center"
+            android:src="@drawable/recents_lock_to_app_pin" />
+    </com.android.systemui.statusbar.AlphaOptimizedFrameLayout>
 
-        <!-- The incompatible app toast -->
-        <ViewStub android:id="@+id/incompatible_app_toast_stub"
-                    android:inflatedId="@+id/incompatible_app_toast"
-                    android:layout="@*android:layout/transient_notification"
-                    android:layout_width="wrap_content"
-                    android:layout_height="wrap_content"
-                    android:layout_gravity="top|center_horizontal"
-                    android:layout_marginTop="48dp"
-                    android:layout_marginLeft="16dp"
-                    android:layout_marginRight="16dp" />
-    </FrameLayout>
+    <!-- The incompatible app toast -->
+    <ViewStub android:id="@+id/incompatible_app_toast_stub"
+                android:inflatedId="@+id/incompatible_app_toast"
+                android:layout="@*android:layout/transient_notification"
+                android:layout_width="wrap_content"
+                android:layout_height="wrap_content"
+                android:layout_gravity="top|center_horizontal"
+                android:layout_marginTop="48dp"
+                android:layout_marginLeft="16dp"
+                android:layout_marginRight="16dp" />
 </com.android.systemui.recents.views.TaskView>
 
 
diff --git a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml b/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
deleted file mode 100644
index 766ef60..0000000
--- a/packages/SystemUI/res/layout/recents_tv_task_card_view.xml
+++ /dev/null
@@ -1,97 +0,0 @@
-<?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.
--->
-<com.android.systemui.recents.tv.views.TaskCardView
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:layout_width="wrap_content"
-    android:layout_height="wrap_content"
-    android:focusable="true"
-    android:focusableInTouchMode="true"
-    android:layout_gravity="center"
-    android:layout_centerInParent="true"
-    android:orientation="vertical"
-    android:layoutDirection="ltr">
-
-    <LinearLayout
-            android:id="@+id/recents_tv_card"
-            android:layout_width="@dimen/recents_tv_card_width"
-            android:layout_height="wrap_content"
-            android:layout_centerInParent="true"
-            android:layout_gravity="center"
-            android:orientation="vertical" >
-        <LinearLayout
-                android:id="@+id/card_info_field"
-                android:layout_width="match_parent"
-                android:layout_height="wrap_content">
-            <ImageView
-                    android:id="@+id/card_extra_badge"
-                    android:layout_width="@dimen/recents_tv_card_extra_badge_size"
-                    android:layout_height="@dimen/recents_tv_card_extra_badge_size"
-                    android:layout_marginBottom="@dimen/recents_tv_icon_padding_bottom"
-                    android:layout_marginEnd="@dimen/recents_tv_icon_padding_end"
-                    android:scaleType="fitCenter"
-                    android:layout_centerVertical="true"
-                    android:layout_alignParentRight="true" />
-            <TextView
-                    android:id="@+id/card_title_text"
-                    android:layout_width="match_parent"
-                    android:layout_height="wrap_content"
-                    android:layout_alignParentTop="false"
-                    android:includeFontPadding="true"
-                    android:minLines="1"
-                    android:maxLines="1"
-                    android:textColor="@color/recents_tv_card_title_text_color"
-                    android:fontFamily="@string/font_roboto_regular"
-                    android:textSize="@dimen/recents_tv_title_text_size"
-                    android:layout_marginBottom="@dimen/recents_tv_text_padding_bottom"
-                    android:ellipsize="end"/>
-        </LinearLayout>
-        <ImageView
-                android:id="@+id/card_view_thumbnail"
-                android:layout_width="match_parent"
-                android:layout_height="@dimen/recents_tv_screenshot_height"
-                android:scaleType="centerCrop"
-                android:gravity="center"
-                android:layout_alignParentTop="true"
-                android:layout_centerHorizontal="true"
-                android:layout_below="@id/card_title_text" />
-    </LinearLayout>
-    <LinearLayout
-            android:id="@+id/card_dismiss"
-            android:layout_width="match_parent"
-            android:layout_height="wrap_content"
-            android:orientation="vertical"
-            android:layout_gravity="center_horizontal"
-            android:layout_below="@id/recents_tv_card"
-            android:alpha="0.0">
-        <ImageView
-                android:id="@+id/card_dismiss_icon"
-                android:layout_width="@dimen/recents_tv_dismiss_icon_size"
-                android:layout_height="@dimen/recents_tv_dismiss_icon_size"
-                android:layout_gravity="center_horizontal"
-                android:layout_marginTop="@dimen/recents_tv_dismiss_icon_top_margin"
-                android:layout_marginBottom="@dimen/recents_tv_dismiss_icon_bottom_margin"
-                android:src="@drawable/ic_cancel_white_24dp" />
-        <TextView
-                android:id="@+id/card_dismiss_text"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:textSize="@dimen/recents_tv_dismiss_text_size"
-                android:fontFamily="@string/font_roboto_light"
-                android:textColor="@color/recents_tv_dismiss_text_color"
-                android:text="@string/recents_tv_dismiss"
-                android:layout_gravity="center_horizontal" />
-    </LinearLayout>
-</com.android.systemui.recents.tv.views.TaskCardView>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/tv_pip_control_button.xml b/packages/SystemUI/res/layout/tv_pip_control_button.xml
new file mode 100644
index 0000000..0beeda1
--- /dev/null
+++ b/packages/SystemUI/res/layout/tv_pip_control_button.xml
@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+**
+** 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.
+*/
+-->
+
+<!-- Layout for {@link com.android.systemui.tv.pip.PipControlButtonView}. -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <ImageView android:id="@+id/button"
+        android:layout_width="34dp"
+        android:layout_height="34dp"
+        android:padding="5dp"
+        android:focusable="true"
+        android:src="@drawable/ic_fullscreen_white_24dp"
+        android:background="@drawable/tv_pip_button_focused"
+        android:layerType="software" />
+
+    <TextView android:id="@+id/desc"
+        android:layout_width="100dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="3dp"
+        android:gravity="center"
+        android:text="@string/pip_fullscreen"
+        android:alpha="0"
+        android:fontFamily="sans-serif"
+        android:textSize="12sp"
+        android:textColor="#EEEEEE" />
+</merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_controls.xml b/packages/SystemUI/res/layout/tv_pip_controls.xml
index 563441f..0a2f320 100644
--- a/packages/SystemUI/res/layout/tv_pip_controls.xml
+++ b/packages/SystemUI/res/layout/tv_pip_controls.xml
@@ -20,77 +20,26 @@
 <!-- Layout for {@link com.android.systemui.tv.pip.PipControlsView}. -->
 <merge xmlns:android="http://schemas.android.com/apk/res/android">
 
-    <LinearLayout
+    <com.android.systemui.tv.pip.PipControlButtonView
+        android:id="@+id/full_button"
         android:layout_width="100dp"
         android:layout_height="wrap_content"
-        android:orientation="vertical"
-        android:gravity="center">
+        android:src="@drawable/ic_fullscreen_white_24dp"
+        android:text="@string/pip_fullscreen" />
 
-        <ImageView android:id="@+id/full_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:focusable="true"
-            android:src="@drawable/tv_pip_full_button" />
-
-        <TextView android:id="@+id/full_desc"
-            android:layout_width="100dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="3dp"
-            android:gravity="center"
-            android:visibility="invisible"
-            android:text="@string/pip_fullscreen"
-            android:fontFamily="sans-serif"
-            android:textSize="12sp"
-            android:textColor="#EEEEEE" />
-    </LinearLayout>
-
-    <LinearLayout
+    <com.android.systemui.tv.pip.PipControlButtonView
+        android:id="@+id/close_button"
         android:layout_width="100dp"
         android:layout_height="wrap_content"
         android:layout_marginStart="-50dp"
-        android:orientation="vertical"
-        android:gravity="center">
+        android:src="@drawable/ic_close_white"
+        android:text="@string/pip_close" />
 
-        <ImageView android:id="@+id/close_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:focusable="true"
-            android:src="@drawable/tv_pip_close_button" />
-
-        <TextView android:id="@+id/close_desc"
-            android:layout_width="100dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="3dp"
-            android:gravity="center"
-            android:visibility="invisible"
-            android:text="@string/pip_close"
-            android:fontFamily="sans-serif"
-            android:textSize="12sp"
-            android:textColor="#EEEEEE" />
-    </LinearLayout>
-
-    <LinearLayout android:id="@+id/play_pause"
+    <com.android.systemui.tv.pip.PipControlButtonView
+        android:id="@+id/play_pause_button"
         android:layout_width="100dp"
         android:layout_height="wrap_content"
         android:layout_marginStart="-50dp"
-        android:orientation="vertical"
-        android:gravity="center" >
-
-        <ImageView android:id="@+id/play_pause_button"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:focusable="true"
-            android:src="@drawable/tv_pip_pause_button" />
-
-        <TextView android:id="@+id/play_pause_desc"
-            android:layout_width="100dp"
-            android:layout_height="wrap_content"
-            android:layout_marginTop="3dp"
-            android:gravity="center"
-            android:visibility="invisible"
-            android:text="@string/pip_pause"
-            android:fontFamily="sans-serif"
-            android:textSize="12sp"
-            android:textColor="#EEEEEE" />
-    </LinearLayout>
+        android:src="@drawable/ic_pause_white_24dp"
+        android:text="@string/pip_pause" />
 </merge>
diff --git a/packages/SystemUI/res/layout/tv_pip_menu.xml b/packages/SystemUI/res/layout/tv_pip_menu.xml
index 2647a99..72a4929 100644
--- a/packages/SystemUI/res/layout/tv_pip_menu.xml
+++ b/packages/SystemUI/res/layout/tv_pip_menu.xml
@@ -29,5 +29,6 @@
     <com.android.systemui.tv.pip.PipControlsView
         android:id="@+id/pip_controls"
         android:layout_width="wrap_content"
-        android:layout_height="wrap_content" />
+        android:layout_height="wrap_content"
+        android:alpha="0" />
 </LinearLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_onboarding.xml b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
index b0814cf..288ad1e 100644
--- a/packages/SystemUI/res/layout/tv_pip_onboarding.xml
+++ b/packages/SystemUI/res/layout/tv_pip_onboarding.xml
@@ -17,47 +17,81 @@
 */
 -->
 
-<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/pip_onboarding"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
-    android:background="#C00288D1"
-    android:gravity="top|center_horizontal"
+    android:background="#B3000000"
     android:orientation="vertical">
 
-    <!-- A rectangle arounds the PIP.
-         Size and positions will be programatically set up
-         to comply with config_defaultPictureInPictureBounds. -->
     <ImageView
-        android:id="@+id/pip_outline"
-        android:layout_width="0dp"
-        android:layout_height="0dp"
-        android:src="@drawable/tv_pip_outline" />
+        android:id="@+id/remote"
+        android:layout_width="72dp"
+        android:layout_height="273dp"
+        android:layout_marginTop="136dp"
+        android:layout_marginStart="304dp"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"
+        android:adjustViewBounds="true"
+        android:src="@drawable/remote"
+        android:alpha="0" />
+    <ImageView
+        android:id="@+id/remote_button"
+        android:layout_width="50dp"
+        android:layout_height="50dp"
+        android:layout_marginTop="256dp"
+        android:layout_marginStart="315dp"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"
+        android:scaleType="fitXY"
+        android:src="@drawable/tv_pip_onboarding_remote"
+        android:alpha="0" />
     <TextView
+        android:id="@+id/title"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_marginTop="24dp"
-        android:paddingStart="24dp"
-        android:paddingEnd="24dp"
+        android:layout_marginTop="188dp"
+        android:layout_marginStart="406dp"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentStart="true"
         android:fontFamily="sans-serif"
-        android:textSize="16sp"
+        android:textSize="24sp"
         android:textColor="#EEEEEE"
-        android:lineSpacingMultiplier="1.28"
-        android:gravity="top|center_horizontal"
-        android:text="@string/pip_onboarding_description" />
+        android:text="@string/pip_onboarding_title"
+        android:alpha="0" />
+    <TextView
+        android:id="@+id/description"
+        android:layout_width="200dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="4dp"
+        android:layout_marginStart="408dp"
+        android:layout_below="@id/title"
+        android:layout_alignParentStart="true"
+        android:fontFamily="sans-serif"
+        android:textSize="14sp"
+        android:textColor="#EEEEEE"
+        android:lineSpacingMultiplier="1.46286"
+        android:text="@string/pip_onboarding_description"
+        android:alpha="0" />
     <Button
-        android:id="@+id/close"
+        android:id="@+id/button"
         android:layout_width="wrap_content"
-        android:layout_height="36dp"
-        android:layout_marginTop="24dp"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="16dp"
+        android:layout_marginStart="408dp"
+        android:layout_below="@id/description"
+        android:layout_alignParentStart="true"
         android:gravity="center"
+        android:paddingTop="10dp"
+        android:paddingBottom="10dp"
         android:paddingStart="24dp"
         android:paddingEnd="24dp"
         android:fontFamily="sans-serif-condensed"
         android:textSize="16sp"
-        android:textColor="#026089"
+        android:textColor="#FFFFFF"
         android:textAllCaps="true"
         android:text="@string/pip_onboarding_button"
-        android:background="#EEEEEE"
+        android:alpha="0"
+        android:background="#009688"
         android:elevation="4dp" />
-</LinearLayout>
+</RelativeLayout>
diff --git a/packages/SystemUI/res/layout/tv_pip_overlay.xml b/packages/SystemUI/res/layout/tv_pip_overlay.xml
index 64bf3b5..608680c 100644
--- a/packages/SystemUI/res/layout/tv_pip_overlay.xml
+++ b/packages/SystemUI/res/layout/tv_pip_overlay.xml
@@ -19,7 +19,8 @@
 
 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
-    android:layout_height="match_parent">
+    android:layout_height="match_parent"
+    android:background="@drawable/tv_pip_overlay_background">
 
     <TextView
         android:id="@+id/guide_overlay"
@@ -33,7 +34,7 @@
         android:textSize="14sp"
         android:textColor="#EEEEEE"
         android:fontFamily="sans-serif"
-        android:background="@drawable/tv_pip_overlay_background"
+        android:background="@drawable/tv_pip_overlay_text_background"
         android:lineSpacingMultiplier="1.465"
         android:gravity="center"
         android:maxLines="2"
diff --git a/packages/SystemUI/res/values/colors_tv.xml b/packages/SystemUI/res/values/colors_tv.xml
index 4126d3c..3817da0 100644
--- a/packages/SystemUI/res/values/colors_tv.xml
+++ b/packages/SystemUI/res/values/colors_tv.xml
@@ -17,7 +17,8 @@
  */
 -->
 <resources>
-    <color name="recents_tv_card_background_color">#FF37474F</color>
+    <color name="recents_tv_card_background_color">#FF263238</color>
     <color name="recents_tv_card_title_text_color">#CCEEEEEE</color>
     <color name="recents_tv_dismiss_text_color">#7FEEEEEE</color>
+    <color name="recents_tv_text_shadow_color">#7F000000</color>
 </resources>
\ No newline at end of file
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index cf2e338..03b9837 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -606,8 +606,8 @@
     <dimen name="recents_layout_z_min">3dp</dimen>
     <dimen name="recents_layout_z_max">24dp</dimen>
 
-    <!-- The margin between the freeform and stack.  We also don't want this to change across 
-         configurations that Recents can be opened in, so we define them statically for all 
+    <!-- The margin between the freeform and stack.  We also don't want this to change across
+         configurations that Recents can be opened in, so we define them statically for all
          display sizes. -->
     <dimen name="recents_freeform_layout_bottom_margin">16dp</dimen>
 
@@ -651,4 +651,7 @@
 
     <!-- The amount to translate when animating the removal of a task. -->
     <dimen name="recents_task_view_remove_anim_translation_x">100dp</dimen>
+
+    <!-- The alpha to apply to the recents row when it doesn't have focus -->
+    <item name="recents_recents_row_dim_alpha" format="float" type="dimen">0.5</item>
 </resources>
diff --git a/packages/SystemUI/res/values/dimens_tv.xml b/packages/SystemUI/res/values/dimens_tv.xml
index f536f86..367dd1d 100644
--- a/packages/SystemUI/res/values/dimens_tv.xml
+++ b/packages/SystemUI/res/values/dimens_tv.xml
@@ -21,11 +21,13 @@
     <dimen name="recents_tv_card_width">240dip</dimen>
     <dimen name="recents_tv_screenshot_height">135dip</dimen>
     <dimen name="recents_tv_card_extra_badge_size">20dip</dimen>
-    <dimen name="recents_tv_banner_width">114dip</dimen>
-    <dimen name="recents_tv_banner_height">64dip</dimen>
+    <dimen name="recents_tv_banner_width">130dip</dimen>
+    <dimen name="recents_tv_banner_height">72dip</dimen>
+    <dimen name="recents_tv_fallback_icon_width">40dip</dimen>
+    <dimen name="recents_tv_fallback_icon_height">40dip</dimen>
     <dimen name="recents_tv_banner_margin_top">16dip</dimen>
     <dimen name="recents_tv_icon_padding_bottom">8dip</dimen>
-    <dimen name="recents_tv_icon_padding_end">12dip</dimen>
+    <dimen name="recents_tv_text_padding_start">12dip</dimen>
     <dimen name="recents_tv_text_padding_bottom">12dip</dimen>
 
     <!-- Padding for grid view in recents view on tv -->
@@ -54,8 +56,6 @@
 
     <!-- Extra space around the PIP and its outline in PIP onboarding activity  -->
     <dimen name="tv_pip_bounds_space">3dp</dimen>
-    <!-- Extra space around the PIP control button icon to match with the focused circle -->
-    <dimen name="tv_pip_button_icon_padding">5dp</dimen>
 
     <!-- Values for entering Recents and exiting Recents -->
     <dimen name="recents_tv_home_recents_shift">125dip</dimen>
diff --git a/packages/SystemUI/res/values/integers_tv.xml b/packages/SystemUI/res/values/integers_tv.xml
index 6984d5a..ebfd8ab 100644
--- a/packages/SystemUI/res/values/integers_tv.xml
+++ b/packages/SystemUI/res/values/integers_tv.xml
@@ -24,4 +24,7 @@
     <integer name="recents_home_duration">400</integer>
     <!-- Delay between the start of slide in animation for each card. -->
     <integer name="recents_home_delay">40</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 dc9ffa9..a4d7a18 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1595,4 +1595,7 @@
     <!-- accessibility label for button to expand quick settings [CHAR LIMIT=NONE] -->
     <string name="accessibility_quick_settings_expand">Expand quick 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>
+
 </resources>
diff --git a/packages/SystemUI/res/values/strings_tv.xml b/packages/SystemUI/res/values/strings_tv.xml
index 52aba0d..dcd1654 100644
--- a/packages/SystemUI/res/values/strings_tv.xml
+++ b/packages/SystemUI/res/values/strings_tv.xml
@@ -31,8 +31,10 @@
     <string name="pip_hold_home">Hold <b>HOME</b> to control PIP</string>
     <!-- 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>
     <!-- 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">Press and hold the HOME button to control PIP</string>
+    <string name="pip_onboarding_description">To control PIP press and hold the <b>HOME</b> button on the remote</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/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index f892fd6..1abd073 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1477,12 +1477,14 @@
     private void sendUserPresentBroadcast() {
         synchronized (this) {
             if (mBootCompleted) {
-                final UserHandle currentUser = new UserHandle(KeyguardUpdateMonitor.getCurrentUser());
+                int currentUserId = KeyguardUpdateMonitor.getCurrentUser();
+                final UserHandle currentUser = new UserHandle(currentUserId);
                 final UserManager um = (UserManager) mContext.getSystemService(
                         Context.USER_SERVICE);
                 for (int profileId : um.getProfileIdsWithDisabled(currentUser.getIdentifier())) {
                     mContext.sendBroadcastAsUser(USER_PRESENT_INTENT, UserHandle.of(profileId));
                 }
+                getLockPatternUtils().userPresent(currentUserId);
             } else {
                 mBootSendUserPresent = true;
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
index 5cb46ac..e050b0d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PageIndicator.java
@@ -60,6 +60,8 @@
 
     public void setLocation(float location) {
         int index = (int) location;
+        setContentDescription(getContext().getString(R.string.accessibility_quick_settings_page,
+                (index + 1), getChildCount()));
         int position = index << 1 | ((location != index) ? 1 : 0);
         if (DEBUG) Log.d(TAG, "setLocation " + location + " " + index + " " + position);
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
index e8e17b1..8925d45 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -387,7 +387,7 @@
                 }
             }
         }
-        if (mTiles.get(mTiles.size() - 1) == null) {
+        if (mTiles.size() - 1 == mTileDividerIndex) {
             mTiles.remove(mTiles.size() - 1);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 6b476ee..4d69280 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -66,6 +66,7 @@
 import com.android.systemui.recents.events.ui.StackViewScrolledEvent;
 import com.android.systemui.recents.events.ui.UpdateFreeformTaskViewVisibilityEvent;
 import com.android.systemui.recents.events.ui.UserInteractionEvent;
+import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
 import com.android.systemui.recents.events.ui.focus.DismissFocusedTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusNextTaskViewEvent;
 import com.android.systemui.recents.events.ui.focus.FocusPreviousTaskViewEvent;
@@ -97,7 +98,7 @@
 
     private RecentsPackageMonitor mPackageMonitor;
     private long mLastTabKeyEventTime;
-    private int mLastOrientation = Configuration.ORIENTATION_UNDEFINED;
+    private int mLastDeviceOrientation = Configuration.ORIENTATION_UNDEFINED;
     private boolean mFinishedOnStartup;
     private boolean mIgnoreAltTabRelease;
     private boolean mIsVisible;
@@ -275,7 +276,7 @@
         getWindow().getAttributes().privateFlags |=
                 WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY;
 
-        mLastOrientation = getResources().getConfiguration().orientation;
+        mLastDeviceOrientation = Utilities.getAppConfiguration(this).orientation;
         mFocusTimerDuration = getResources().getInteger(R.integer.recents_auto_advance_duration);
         mIterateTrigger = new DozeTrigger(mFocusTimerDuration, new Runnable() {
             @Override
@@ -425,13 +426,12 @@
     public void onConfigurationChanged(Configuration newConfig) {
         super.onConfigurationChanged(newConfig);
 
-
         // Notify of the config change
-        int newOrientation = getResources().getConfiguration().orientation;
+        int newDeviceOrientation = Utilities.getAppConfiguration(this).orientation;
         int numStackTasks = mRecentsView.getStack().getStackTaskCount();
         EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */,
-                (mLastOrientation != newOrientation), numStackTasks > 0));
-        mLastOrientation = newOrientation;
+                (mLastDeviceOrientation != newDeviceOrientation), numStackTasks > 0));
+        mLastDeviceOrientation = newDeviceOrientation;
     }
 
     @Override
@@ -454,7 +454,7 @@
         int numStackTasks = stack.getStackTaskCount();
 
         EventBus.getDefault().send(new ConfigurationChangedEvent(true /* fromMultiWindow */,
-                false /* fromOrientationChange */, numStackTasks > 0));
+                false /* fromDeviceOrientationChange */, numStackTasks > 0));
 
         if (mRecentsView != null) {
             mRecentsView.updateStack(stack);
@@ -752,6 +752,13 @@
         mIgnoreAltTabRelease = true;
     }
 
+    public final void onBusEvent(final DragEndEvent event) {
+        // Handle the case where we drop onto a dock region
+        if (event.dropTarget instanceof TaskStack.DockState) {
+            mScrimViews.animateScrimToCurrentNavBarState(false /* hasStackTasks */);
+        }
+    }
+
     @Override
     public boolean onPreDraw() {
         mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
@@ -769,6 +776,8 @@
     @Override
     public void dump(String prefix, FileDescriptor fd, PrintWriter writer, String[] args) {
         super.dump(prefix, fd, writer, args);
+        EventBus.getDefault().dump(prefix, writer);
+
         String id = Integer.toHexString(System.identityHashCode(this));
 
         writer.print(prefix); writer.print(TAG);
@@ -779,6 +788,5 @@
         if (mRecentsView != null) {
             mRecentsView.dump(prefix, writer);
         }
-        EventBus.getDefault().dump(prefix, writer);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index fda340d..c230cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -175,7 +175,11 @@
         ssp.registerTaskStackListener(mTaskStackListener);
 
         // Initialize the static configuration resources
-        reloadHeaderBarLayout();
+        LayoutInflater inflater = LayoutInflater.from(mContext);
+        mDummyStackView = new TaskStackView(mContext);
+        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
+                null, false);
+        reloadResources();
 
         // When we start, preload the data associated with the previous recent tasks.
         // We can use a new plan since the caches will be the same.
@@ -194,7 +198,9 @@
     }
 
     public void onConfigurationChanged() {
-        reloadHeaderBarLayout();
+        reloadResources();
+        mDummyStackView.reloadOnConfigurationChange();
+        mHeaderBar.onConfigurationChanged();
     }
 
     /**
@@ -542,11 +548,10 @@
     }
 
     /**
-     * Reloads all the layouts for the header bar transition.
+     * Reloads all the resources for the current configuration.
      */
-    private void reloadHeaderBarLayout() {
+    private void reloadResources() {
         Resources res = mContext.getResources();
-        LayoutInflater inflater = LayoutInflater.from(mContext);
 
         mStatusBarHeight = res.getDimensionPixelSize(
                 com.android.internal.R.dimen.status_bar_height);
@@ -561,9 +566,6 @@
                 R.dimen.recents_task_view_header_height_tablet_land,
                 R.dimen.recents_task_view_header_height,
                 R.dimen.recents_task_view_header_height_tablet_land);
-        mDummyStackView = new TaskStackView(mContext);
-        mHeaderBar = (TaskViewHeader) inflater.inflate(R.layout.recents_task_view_header,
-                null, false);
     }
 
     /**
@@ -687,7 +689,7 @@
             TaskStackViewScroller stackScroller = stackView.getScroller();
 
             stackView.updateLayoutAlgorithm(true /* boundScroll */);
-            stackView.updateToInitialState(true /* scrollToInitialState */);
+            stackView.updateToInitialState();
 
             for (int i = tasks.size() - 1; i >= 0; i--) {
                 Task task = tasks.get(i);
@@ -740,7 +742,7 @@
 
         // Get the transform for the running task
         stackView.updateLayoutAlgorithm(true /* boundScroll */);
-        stackView.updateToInitialState(true /* scrollToInitialState */);
+        stackView.updateToInitialState();
         stackView.getStackAlgorithm().getStackTransformScreenCoordinates(launchTask,
                 stackView.getScroller().getStackScroll(), mTmpTransform, null);
         return mTmpTransform;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
index e3bc2a7..53b67cf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/activity/ConfigurationChangedEvent.java
@@ -24,13 +24,13 @@
 public class ConfigurationChangedEvent extends EventBus.AnimatedEvent {
 
     public final boolean fromMultiWindow;
-    public final boolean fromOrientationChange;
+    public final boolean fromDeviceOrientationChange;
     public final boolean hasStackTasks;
 
-    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromOrientationChange,
+    public ConfigurationChangedEvent(boolean fromMultiWindow, boolean fromDeviceOrientationChange,
             boolean hasStackTasks) {
         this.fromMultiWindow = fromMultiWindow;
-        this.fromOrientationChange = fromOrientationChange;
+        this.fromDeviceOrientationChange = fromDeviceOrientationChange;
         this.hasStackTasks = hasStackTasks;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
index 4ecda54..f6cc12b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java
@@ -18,8 +18,11 @@
 
 import android.animation.Animator;
 import android.animation.AnimatorSet;
+import android.animation.RectEvaluator;
 import android.annotation.FloatRange;
 import android.app.Activity;
+import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.graphics.Rect;
@@ -71,7 +74,7 @@
             };
 
     public static final RectFEvaluator RECTF_EVALUATOR = new RectFEvaluator();
-
+    public static final RectEvaluator RECT_EVALUATOR = new RectEvaluator(new Rect());
     public static final Rect EMPTY_RECT = new Rect();
 
     /**
@@ -270,6 +273,14 @@
     }
 
     /**
+     * Returns the application configuration, which is independent of the activity's current
+     * configuration in multiwindow.
+     */
+    public static Configuration getAppConfiguration(Context context) {
+        return context.getApplicationContext().getResources().getConfiguration();
+    }
+
+    /**
      * Returns a lightweight dump of a rect.
      */
     public static String dumpRect(Rect r) {
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 9f9c48f..68c46a9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -315,6 +315,15 @@
         return key.id != affiliationTaskId;
     }
 
+    /**
+     * Returns the top activity component.
+     */
+    public ComponentName getTopComponent() {
+        return topActivity != null
+                ? topActivity
+                : key.baseIntent.getComponent();
+    }
+
     @Override
     public boolean equals(Object o) {
         // Check that the id matches
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 fbb5987..95e276f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -299,7 +299,7 @@
                 if (bounds != null && !dockAreaOverlay.getBounds().equals(bounds)) {
                     if (animateBounds) {
                         PropertyValuesHolder prop = PropertyValuesHolder.ofObject(
-                                Utilities.DRAWABLE_RECT, new RectEvaluator(new Rect()),
+                                Utilities.DRAWABLE_RECT, Utilities.RECT_EVALUATOR,
                                 dockAreaOverlay.getBounds(), bounds);
                         animators.add(ObjectAnimator.ofPropertyValuesHolder(dockAreaOverlay, prop));
                     } else {
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 60a85df..7378102 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/RecentsTvActivity.java
@@ -107,7 +107,9 @@
         public void onMoveToFullscreen() {
             // Recents should be dismissed when PIP moves to fullscreen. If not, Recents will
             // be unnecessarily shown in the scenario: PIP->Fullscreen->PIP.
-            dismissRecentsToLaunchTargetTaskOrHome();
+            // Do not show Recents close animation because PIP->Fullscreen animation will be shown
+            // instead.
+            dismissRecentsToLaunchTargetTaskOrHome(false);
         }
 
         @Override
@@ -118,7 +120,7 @@
             new PipRecentsOverlayManager.Callback() {
                 @Override
                 public void onClosed() {
-                    dismissRecentsToLaunchTargetTaskOrHome();
+                    dismissRecentsToLaunchTargetTaskOrHome(true);
                 }
 
                 @Override
@@ -211,13 +213,15 @@
         }
     }
 
-    boolean dismissRecentsToLaunchTargetTaskOrHome() {
+    boolean dismissRecentsToLaunchTargetTaskOrHome(boolean animate) {
         SystemServicesProxy ssp = Recents.getSystemServices();
         if (ssp.isRecentsTopMost(ssp.getTopMostTask(), null)) {
             // If we have a focused Task, launch that Task now
-            if (mRecentsView.launchPreviousTask()) return true;
+            if (mRecentsView.launchPreviousTask(animate)) {
+              return true;
+            }
             // If none of the other cases apply, then just go Home
-            dismissRecentsToHome(true /* animateTaskViews */);
+            dismissRecentsToHome(animate /* animateTaskViews */);
         }
         return false;
     }
@@ -247,7 +251,7 @@
         dismissEvent.addPostAnimationCallback(mFinishLaunchHomeRunnable);
         dismissEvent.addPostAnimationCallback(closeSystemWindows);
 
-        if(mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
+        if (mTaskStackHorizontalGridView.getChildCount() > 0 && animateTaskViews) {
             mHomeRecentsEnterExitAnimationHolder.startExitAnimation(dismissEvent);
         } else {
             closeSystemWindows.run();
@@ -374,7 +378,7 @@
     public void onEnterAnimationComplete() {
         super.onEnterAnimationComplete();
         if(mLaunchedFromHome) {
-            mHomeRecentsEnterExitAnimationHolder.startEnterAnimation();
+            mHomeRecentsEnterExitAnimationHolder.startEnterAnimation(mPipManager.isPipShown());
         }
         EventBus.getDefault().send(new EnterRecentsWindowAnimationCompletedEvent());
     }
@@ -463,7 +467,7 @@
         if (launchState.launchedFromHome) {
             dismissRecentsToHome(true /* animateTaskViews */);
         } else {
-            dismissRecentsToLaunchTargetTaskOrHome();
+            dismissRecentsToLaunchTargetTaskOrHome(true);
         }
     }
 
@@ -561,6 +565,8 @@
             // as if it's the part of the Recents UI.
             mPipRecentsOverlayManager.requestFocus(
                     mTaskStackViewAdapter.getItemCount() > 0);
+        } else {
+            mPipRecentsOverlayManager.clearFocus();
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
index 3e668af..66d8576 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/DismissAnimationsHolder.java
@@ -18,6 +18,7 @@
 
 import android.animation.Animator;
 import android.content.res.Resources;
+import android.view.View;
 import android.widget.LinearLayout;
 import com.android.systemui.Interpolators;
 import com.android.systemui.recents.tv.views.TaskCardView;
@@ -26,17 +27,20 @@
 
 public class DismissAnimationsHolder {
     private LinearLayout mDismissArea;
-    private LinearLayout mRecentsTvCard;
-    private int mCardYDelta;
+    private LinearLayout mInfoField;
+    private View mThumbnailView;
+    private int mDismissEnterYDelta;
+    private int mDismissStartYDelta;
     private long mShortDuration;
     private long mLongDuration;
 
     public DismissAnimationsHolder(TaskCardView taskCardView) {
-        mRecentsTvCard = (LinearLayout) taskCardView.findViewById(R.id.recents_tv_card);
+        mInfoField = (LinearLayout) taskCardView.findViewById(R.id.card_info_field);
         mDismissArea = (LinearLayout) taskCardView.findViewById(R.id.card_dismiss);
-
+        mThumbnailView = taskCardView.findViewById(R.id.card_view_thumbnail);
         Resources res = taskCardView.getResources();
-        mCardYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+        mDismissEnterYDelta = res.getDimensionPixelOffset(R.dimen.recents_tv_dismiss_shift_down);
+        mDismissStartYDelta = mDismissEnterYDelta * 2;
         mShortDuration =  res.getInteger(R.integer.dismiss_short_duration);
         mLongDuration =  res.getInteger(R.integer.dismiss_long_duration);
     }
@@ -47,10 +51,16 @@
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .alpha(1.0f);
 
-        mRecentsTvCard.animate()
+        mInfoField.animate()
                 .setDuration(mShortDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(mCardYDelta)
+                .translationY(mDismissEnterYDelta)
+                .alpha(0.5f);
+
+        mThumbnailView.animate()
+                .setDuration(mShortDuration)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .translationY(mDismissEnterYDelta)
                 .alpha(0.5f);
     }
 
@@ -60,10 +70,16 @@
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .alpha(0.0f);
 
-        mRecentsTvCard.animate()
+        mInfoField.animate()
                 .setDuration(mShortDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(-mCardYDelta)
+                .translationY(0)
+                .alpha(1.0f);
+
+        mThumbnailView.animate()
+                .setDuration(mShortDuration)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .translationY(0)
                 .alpha(1.0f);
     }
 
@@ -73,17 +89,25 @@
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
                 .alpha(0.0f);
 
-        mRecentsTvCard.animate()
+        mInfoField.animate()
                 .setDuration(mLongDuration)
                 .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
-                .translationYBy(mCardYDelta)
+                .translationY(mDismissStartYDelta)
                 .alpha(0.0f)
                 .setListener(listener);
+
+        mThumbnailView.animate()
+                .setDuration(mLongDuration)
+                .setInterpolator(Interpolators.FAST_OUT_SLOW_IN)
+                .translationY(mDismissStartYDelta)
+                .alpha(0.0f);
     }
 
     public void reset() {
-        mRecentsTvCard.setAlpha(1.0f);
-        mRecentsTvCard.setTranslationY(0);
-        mRecentsTvCard.animate().setListener(null);
+        mInfoField.setAlpha(1.0f);
+        mInfoField.setTranslationY(0);
+        mInfoField.animate().setListener(null);
+        mThumbnailView.setAlpha(1.0f);
+        mThumbnailView.setTranslationY(0);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
index 278de87..92718a3 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/HomeRecentsEnterExitAnimationHolder.java
@@ -28,6 +28,7 @@
 
     private Context mContext;
     private TaskStackHorizontalGridView mGridView;
+    private float mDimAlpha;
     private long mDelay;
     private int mDuration;
     private int mTranslationX;
@@ -36,19 +37,19 @@
             TaskStackHorizontalGridView gridView) {
         mContext = context;
         mGridView = gridView;
+        mDimAlpha = mContext.getResources().getFloat(R.dimen.recents_recents_row_dim_alpha);
         mTranslationX = mContext.getResources()
                 .getDimensionPixelSize(R.dimen.recents_tv_home_recents_shift);
         mDelay = mContext.getResources().getInteger(R.integer.recents_home_delay);
         mDuration =  mContext.getResources().getInteger(R.integer.recents_home_duration);
     }
 
-    public void startEnterAnimation() {
+    public void startEnterAnimation(boolean isPipShown) {
         for(int i = 0; i < mGridView.getChildCount(); i++) {
             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
             view.setTranslationX(-mTranslationX);
-            view.setAlpha(0.0f);
             view.animate()
-                    .alpha(1.0f)
+                    .alpha(isPipShown ? mDimAlpha : 1.0f)
                     .translationX(0)
                     .setDuration(mDuration)
                     .setStartDelay(mDelay * i)
@@ -76,7 +77,7 @@
     public void setEnterFromHomeStartingAnimationValues() {
         for(int i = 0; i < mGridView.getChildCount(); i++) {
             TaskCardView view = (TaskCardView) mGridView.getChildAt(i);
-            view.setTranslationX(-mTranslationX);
+            view.setTranslationX(0);
             view.setAlpha(0.0f);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
index 28abc34..160835f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/RecentsRowFocusAnimationHolder.java
@@ -29,8 +29,6 @@
  * Recents row's focus animation with PIP controls.
  */
 public class RecentsRowFocusAnimationHolder {
-    private static final float DIM_ALPHA = 0.5f;
-
     private View mView;
     private View mTitleView;
 
@@ -43,6 +41,7 @@
 
         Resources res = view.getResources();
         int duration = res.getInteger(R.integer.recents_tv_pip_focus_anim_duration);
+        float dimAlpha = res.getFloat(R.dimen.recents_recents_row_dim_alpha);
 
         mFocusGainAnimatorSet = new AnimatorSet();
         mFocusGainAnimatorSet.playTogether(
@@ -53,7 +52,7 @@
 
         mFocusLoseAnimatorSet = new AnimatorSet();
         mFocusLoseAnimatorSet.playTogether(
-                ObjectAnimator.ofFloat(mView, "alpha", DIM_ALPHA),
+                ObjectAnimator.ofFloat(mView, "alpha", dimAlpha),
                 ObjectAnimator.ofFloat(mTitleView, "alpha", 0f));
         mFocusLoseAnimatorSet.setDuration(duration);
         mFocusLoseAnimatorSet.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
index 888561c..9edd5af 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/animations/ViewFocusAnimator.java
@@ -26,6 +26,7 @@
 import android.view.animation.Interpolator;
 
 import com.android.systemui.R;
+import com.android.systemui.recents.tv.views.TaskCardView;
 
 public class ViewFocusAnimator implements View.OnFocusChangeListener {
     private final float mUnselectedScale;
@@ -94,10 +95,13 @@
 
         mTargetView.setScaleX(scale);
         mTargetView.setScaleY(scale);
-        mTargetView.setZ(z);
 
         mTargetView.setPadding((int) spacing, mTargetView.getPaddingTop(),
                 (int) spacing, mTargetView.getPaddingBottom());
+
+        if (mTargetView instanceof TaskCardView) {
+            ((TaskCardView) mTargetView).getThumbnailView().setZ(z);
+        }
     }
 
     public float getFocusProgress() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
index fb1127e..812bff1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvTransitionHelper.java
@@ -16,7 +16,6 @@
 package com.android.systemui.recents.tv.views;
 
 import android.annotation.Nullable;
-import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.Context;
 import android.graphics.Bitmap;
@@ -122,11 +121,13 @@
         }
         try {
             Rect taskRect = taskView.getFocusedThumbnailRect();
-            Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
-                    taskRect.height(), false);
-            WindowManagerGlobal.getWindowManagerService()
-                    .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
-                            taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+            if (taskRect != null) {
+                Bitmap thumbnail = Bitmap.createScaledBitmap(task.thumbnail, taskRect.width(),
+                        taskRect.height(), false);
+                WindowManagerGlobal.getWindowManagerService()
+                        .overridePendingAppTransitionAspectScaledThumb(thumbnail, taskRect.left,
+                                taskRect.top, taskRect.width(), taskRect.height(), callback, true);
+            }
         } catch (RemoteException e) {
             Log.w(TAG, "Failed to override transition: " + e);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
index b876fc70..4058c62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/RecentsTvView.java
@@ -18,7 +18,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.os.Handler;
-import android.support.v7.widget.DefaultItemAnimator;
 import android.support.v7.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.util.Log;
@@ -35,7 +34,6 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.CancelEnterRecentsWindowAnimationEvent;
 import com.android.systemui.recents.events.activity.DismissRecentsToHomeAnimationStarted;
-import com.android.systemui.recents.events.activity.ExitRecentsWindowFirstAnimationFrameEvent;
 import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
 import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
 import com.android.systemui.recents.misc.SystemServicesProxy;
@@ -114,7 +112,7 @@
         if (mTaskStackHorizontalView != null) {
             Task task = mTaskStackHorizontalView.getFocusedTask();
             if (task != null) {
-                launchTaskFomRecents(task);
+                launchTaskFomRecents(task, true);
                 return true;
             }
         }
@@ -122,12 +120,12 @@
     }
 
     /** Launches the task that recents was launched from if possible */
-    public boolean launchPreviousTask() {
+    public boolean launchPreviousTask(boolean animate) {
         if (mTaskStackHorizontalView != null) {
             TaskStack stack = mTaskStackHorizontalView.getStack();
             Task task = stack.getLaunchTarget();
             if (task != null) {
-                launchTaskFomRecents(task);
+                launchTaskFomRecents(task, animate);
                 return true;
             }
         }
@@ -139,18 +137,25 @@
      * attempt to scroll to focus the task before launching.
      * @param task
      */
-    private void launchTaskFomRecents(final Task task) {
-        if(task != mTaskStackHorizontalView.getFocusedTask()) {
-            if(mScrollListener != null) {
+    private void launchTaskFomRecents(final Task task, boolean animate) {
+        if (!animate) {
+            SystemServicesProxy ssp = Recents.getSystemServices();
+            ssp.startActivityFromRecents(getContext(), task.key, task.title, null);
+            return;
+        }
+        mTaskStackHorizontalView.requestFocus();
+        Task focusedTask = mTaskStackHorizontalView.getFocusedTask();
+        if (focusedTask != null && task != focusedTask) {
+            if (mScrollListener != null) {
                 mTaskStackHorizontalView.removeOnScrollListener(mScrollListener);
             }
             mScrollListener = new OnScrollListener() {
                 @Override
                 public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
                     super.onScrollStateChanged(recyclerView, newState);
-                    if(newState == RecyclerView.SCROLL_STATE_IDLE) {
+                    if (newState == RecyclerView.SCROLL_STATE_IDLE) {
                         TaskCardView cardView = mTaskStackHorizontalView.getChildViewForTask(task);
-                        if(cardView != null) {
+                        if (cardView != null) {
                             mTransitionHelper.launchTaskFromRecents(mStack, task,
                                     mTaskStackHorizontalView, cardView, null, INVALID_STACK_ID);
                         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
index d3bc4b6..a72a7e6 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskCardView.java
@@ -17,10 +17,15 @@
 
 import android.animation.Animator;
 import android.content.Context;
+import android.content.pm.PackageManager;
+import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Bitmap;
 import android.graphics.Point;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.util.TypedValue;
 import android.view.Display;
 import android.view.KeyEvent;
@@ -38,7 +43,8 @@
 
 public class TaskCardView extends LinearLayout {
 
-    private ImageView mThumbnailView;
+    private static final String TAG = "TaskCardView";
+    private View mThumbnailView;
     private TextView mTitleTextView;
     private ImageView mBadgeView;
     private Task mTask;
@@ -58,26 +64,28 @@
 
     public TaskCardView(Context context, AttributeSet attrs, int defStyleAttr) {
         super(context, attrs, defStyleAttr);
-        mViewFocusAnimator = new ViewFocusAnimator(this);
         mDismissState = false;
+        Configuration config = getResources().getConfiguration();
+        setLayoutDirection(config.getLayoutDirection());
     }
 
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mThumbnailView = (ImageView) findViewById(R.id.card_view_thumbnail);
+        mThumbnailView = findViewById(R.id.card_view_thumbnail);
         mTitleTextView = (TextView) findViewById(R.id.card_title_text);
         mBadgeView = (ImageView) findViewById(R.id.card_extra_badge);
         mDismissAnimationsHolder = new DismissAnimationsHolder(this);
         View title = findViewById(R.id.card_info_field);
         mRecentsRowFocusAnimationHolder = new RecentsRowFocusAnimationHolder(this, title);
+        mViewFocusAnimator = new ViewFocusAnimator(this);
     }
 
     public void init(Task task) {
         mTask = task;
-        mThumbnailView.setImageBitmap(task.thumbnail);
         mTitleTextView.setText(task.title);
         mBadgeView.setImageDrawable(task.icon);
+        setThumbnailView();
     }
 
     public Task getTask() {
@@ -238,4 +246,64 @@
         mRecentsRowFocusAnimationHolder.reset();
         mDismissAnimationsHolder.reset();
     }
+
+    private void setThumbnailView() {
+        ImageView screenshotView = (ImageView) findViewById(R.id.card_view_banner_icon);
+        PackageManager pm = getContext().getPackageManager();
+        if (mTask.thumbnail != null) {
+            setAsScreenShotView(mTask.thumbnail, screenshotView);
+        } else {
+            try {
+                Drawable banner = null;
+                if (mTask.key != null) {
+                    banner = pm.getActivityBanner(mTask.key.baseIntent);
+                }
+                if (banner != null) {
+                    setAsBannerView(banner, screenshotView);
+                } else {
+                    setAsIconView(mTask.icon, screenshotView);
+                }
+            } catch (PackageManager.NameNotFoundException e) {
+                Log.e(TAG, "Package not found : " + e);
+                setAsIconView(mTask.icon, screenshotView);
+            }
+        }
+    }
+
+    private void setAsScreenShotView(Bitmap screenshot, ImageView screenshotView) {
+        LayoutParams lp = (LayoutParams) screenshotView.getLayoutParams();
+        lp.width = getResources()
+                .getDimensionPixelSize(R.dimen.recents_tv_card_width);
+        lp.height = getResources()
+                .getDimensionPixelSize(R.dimen.recents_tv_screenshot_height);
+
+        screenshotView.setLayoutParams(lp);
+        screenshotView.setImageBitmap(screenshot);
+    }
+
+    private void setAsBannerView(Drawable banner, ImageView bannerView) {
+        LayoutParams lp = (LayoutParams) bannerView.getLayoutParams();
+        lp.width = getResources()
+                .getDimensionPixelSize(R.dimen.recents_tv_banner_width);
+        lp.height = getResources()
+                .getDimensionPixelSize(R.dimen.recents_tv_banner_height);
+
+        bannerView.setLayoutParams(lp);
+        bannerView.setImageDrawable(banner);
+    }
+
+    private void setAsIconView(Drawable icon, ImageView iconView) {
+        LayoutParams lp = (LayoutParams) iconView.getLayoutParams();
+        lp.width = getResources()
+                .getDimensionPixelSize(R.dimen.recents_tv_fallback_icon_width);
+        lp.height = getResources()
+                .getDimensionPixelSize(R.dimen.recents_tv_fallback_icon_height);
+
+        iconView.setLayoutParams(lp);
+        iconView.setImageDrawable(icon);
+    }
+
+    public View getThumbnailView() {
+        return mThumbnailView;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
index 77ab8c1..9f52abd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalGridView.java
@@ -33,9 +33,6 @@
 import com.android.systemui.recents.model.TaskStack.TaskStackCallbacks;
 import com.android.systemui.recents.views.AnimationProps;
 
-import java.util.ArrayList;
-import java.util.List;
-
 /**
  * Horizontal Grid View Implementation to show the Task Stack for TV.
  */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
index eff1845..eb3b02d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/tv/views/TaskStackHorizontalViewAdapter.java
@@ -27,7 +27,6 @@
 import com.android.systemui.recents.events.EventBus;
 import com.android.systemui.recents.events.activity.LaunchTvTaskEvent;
 import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
-import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
 import com.android.systemui.recents.model.Task;
 import com.android.systemui.recents.views.AnimationProps;
 
@@ -47,6 +46,7 @@
     public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{
         private TaskCardView mTaskCardView;
         private Task mTask;
+        private boolean mShouldReset;
         public ViewHolder(View v) {
             super(v);
             if(v instanceof TaskCardView) {
@@ -69,7 +69,6 @@
                 } else {
                     EventBus.getDefault().send(new LaunchTvTaskEvent(mTaskCardView, mTask,
                             null, INVALID_STACK_ID));
-                    ((Activity) (v.getContext())).finish();
                 }
             } catch (Exception e) {
                 Log.e(TAG, v.getContext()
@@ -89,6 +88,7 @@
                 public void onAnimationEnd(Animator animation) {
                     removeAt(position);
                     EventBus.getDefault().send(new DeleteTaskDataEvent(task));
+                    mShouldReset = true;
                 }
 
                 @Override
@@ -114,9 +114,9 @@
     @Override
     public TaskStackHorizontalViewAdapter.ViewHolder onCreateViewHolder(ViewGroup parent,
             int viewType) {
-        View view = LayoutInflater.from(parent.getContext())
-                .inflate(R.layout.recents_tv_task_card_view, parent, false);
-        ViewHolder viewHolder = new ViewHolder(view);
+        LayoutInflater inflater = LayoutInflater.from(parent.getContext());
+        ViewHolder viewHolder = new ViewHolder(
+                        inflater.inflate(R.layout.recents_tv_task_card_view, parent, false));
         return viewHolder;
     }
 
@@ -127,7 +127,12 @@
 
     @Override
     public void onViewDetachedFromWindow(ViewHolder holder) {
-        holder.mTaskCardView.reset();
+        // We only want to reset on view detach if this is the last task being dismissed.
+        // This is so that we do not reset when shifting to apps etc, as it is not needed.
+        if (holder.mShouldReset) {
+            holder.mTaskCardView.reset();
+            holder.mShouldReset = false;
+        }
     }
 
     @Override
@@ -157,6 +162,7 @@
         return (position >= 0) ? position : 0;
     }
 
+
     public void setTaskStackHorizontalGridView(TaskStackHorizontalGridView gridView) {
         mGridView = gridView;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
index 9f2b00a..471df6a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/FixedSizeFrameLayout.java
@@ -88,6 +88,10 @@
      */
     protected void layoutContents(Rect bounds, boolean changed) {
         super.onLayout(changed, bounds.left, bounds.top, bounds.right, bounds.bottom);
+
+        int width = getMeasuredWidth();
+        int height = getMeasuredHeight();
+        onSizeChanged(width, height, width, height);
     }
 
 }
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 59b7560..d55c7d8 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -519,7 +519,9 @@
                 @Override
                 public void onAnimationStarted() {
                     EventBus.getDefault().send(new DockedFirstAnimationFrameEvent());
-                    mTaskStackView.getStack().removeTask(event.task, AnimationProps.IMMEDIATE,
+                    // Remove the task and don't bother relaying out, as all the tasks will be
+                    // relaid out when the stack changes on the multiwindow change event
+                    mTaskStackView.getStack().removeTask(event.task, null,
                             true /* fromDockGesture */);
                 }
             };
@@ -541,7 +543,7 @@
                     true /* scaleUp */);
 
             MetricsLogger.action(mContext, MetricsEvent.ACTION_WINDOW_DOCK_DRAG_DROP,
-                    event.task.topActivity.flattenToShortString());
+                    event.task.getTopComponent().flattenToShortString());
         } else {
             // Animate the overlay alpha back to 0
             updateVisibleDockRegions(null, true /* isDefaultDockState */, -1,
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index 5fbc037..70c4dbd 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -162,7 +162,8 @@
         mVisibleDockStates.clear();
         if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()
                 && mDividerSnapAlgorithm.isSplitScreenFeasible()) {
-            Recents.logDockAttempt(mRv.getContext(), event.task.topActivity, event.task.resizeMode);
+            Recents.logDockAttempt(mRv.getContext(), event.task.getTopComponent(),
+                    event.task.resizeMode);
             if (!event.task.isDockable) {
                 EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
             } else {
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 07a1d4e..dce2353 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/SystemBarScrimViews.java
@@ -152,7 +152,7 @@
     /**
      * Animates the scrim to match the state of the current nav bar.
      */
-    private void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
+    public void animateScrimToCurrentNavBarState(boolean hasStackTasks) {
         boolean hasNavBarScrim = isNavBarScrimRequired(hasStackTasks);
         if (mHasNavBarScrim != hasNavBarScrim) {
             AnimationProps animation = hasNavBarScrim
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 fe91f42..76aab59d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java
@@ -19,6 +19,7 @@
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.Resources;
 import android.util.Log;
 import android.view.View;
@@ -77,7 +78,7 @@
 
     public static final int ENTER_FROM_HOME_ALPHA_DURATION = 100;
     public static final int ENTER_FROM_HOME_TRANSLATION_DURATION = 333;
-    public static final int ENTER_WHILE_DOCKING_DURATION = 150;
+    public static final int ENTER_WHILE_DOCKING_DURATION = 250;
 
     private static final PathInterpolator ENTER_FROM_HOME_TRANSLATION_INTERPOLATOR =
             new PathInterpolator(0, 0, 0, 1f);
@@ -135,6 +136,8 @@
                 R.dimen.recents_task_stack_animation_affiliate_enter_offset);
         int launchedWhileDockingOffset = res.getDimensionPixelSize(
                 R.dimen.recents_task_stack_animation_launched_while_docking_offset);
+        boolean isLandscape = mStackView.getContext().getApplicationContext().getResources()
+                .getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE;
 
         // Prepare each of the task views for their enter animation from front to back
         List<TaskView> taskViews = mStackView.getTaskViews();
@@ -169,7 +172,10 @@
                 mTmpTransform.alpha = 0f;
                 mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
             } else if (launchState.launchedViaDockGesture) {
-                mTmpTransform.rect.offset(0, launchedWhileDockingOffset);
+                int offset = isLandscape
+                        ? launchedWhileDockingOffset
+                        : (int) (offscreenYOffset * 0.9f);
+                mTmpTransform.rect.offset(0, offset);
                 mTmpTransform.alpha = 0f;
                 mStackView.updateTaskViewToTransform(tv, mTmpTransform, AnimationProps.IMMEDIATE);
             }
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 e4da8b3..34d6bce 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -297,9 +297,6 @@
     private FreePathInterpolator mUnfocusedDimCurveInterpolator;
     private FreePathInterpolator mFocusedDimCurveInterpolator;
 
-    // Indexed from the front of the stack, the normalized x in the unfocused range for each task
-    private float[] mInitialNormX;
-
     // The state of the stack focus (0..1), which controls the transition of the stack from the
     // focused to non-focused state
     @ViewDebug.ExportedProperty(category="recents")
@@ -406,8 +403,10 @@
     /**
      * Sets the system insets.
      */
-    public void setSystemInsets(Rect systemInsets) {
+    public boolean setSystemInsets(Rect systemInsets) {
+        boolean changed = mSystemInsets.equals(systemInsets);
         mSystemInsets.set(systemInsets);
+        return changed;
     }
 
     /**
@@ -545,13 +544,11 @@
             } else {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex - 1, mMinScrollP, mMaxScrollP);
             }
-            mInitialNormX = null;
         } else if (!ssp.hasFreeformWorkspaceSupport() && mNumStackTasks == 1) {
             // If there is one stack task, ignore the min/max/initial scroll positions
             mMinScrollP = 0;
             mMaxScrollP = 0;
             mInitialScrollP = 0;
-            mInitialNormX = null;
         } else {
             // Set the max scroll to be the point where the front most task is visible with the
             // stack bottom offset
@@ -565,42 +562,50 @@
                     launchState.launchedViaDockGesture;
             if (launchState.launchedWithAltTab) {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
-                mInitialNormX = null;
             } else if (scrollToFront) {
                 mInitialScrollP = Utilities.clamp(launchTaskIndex, mMinScrollP, mMaxScrollP);
-                mInitialNormX = null;
             } else {
                 // We are overriding the initial two task positions, so set the initial scroll
                 // position to match the second task (aka focused task) position
                 float initialTopNormX = getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP);
                 mInitialScrollP = Math.max(mMinScrollP, Math.min(mMaxScrollP, (mNumStackTasks - 2))
                         - Math.max(0, mUnfocusedRange.getAbsoluteX(initialTopNormX)));
-
-                // Set the initial scroll to the predefined state (which differs from the stack)
-                mInitialNormX = new float[] {
-                        getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
-                                FROM_BOTTOM),
-                        initialTopNormX
-                };
             }
         }
     }
 
-    public void updateToInitialState(List<Task> tasks) {
-        if (mInitialNormX == null) {
-            return;
-        }
+    /**
+     * Creates task overrides to ensure the initial stack layout if necessary.
+     */
+    public void setTaskOverridesForInitialState(TaskStack stack) {
+        RecentsActivityLaunchState launchState = Recents.getConfiguration().getLaunchState();
 
-        mUnfocusedRange.offset(0f);
-        int taskCount = tasks.size();
-        for (int i = taskCount - 1; i >= 0; i--) {
-            int indexFromFront = taskCount - i - 1;
-            if (indexFromFront >= mInitialNormX.length) {
-                break;
+        mTaskIndexOverrideMap.clear();
+
+        boolean scrollToFront = launchState.launchedFromHome ||
+                launchState.launchedViaDockGesture;
+        if (getInitialFocusState() == STATE_UNFOCUSED && mNumStackTasks > 1) {
+            if (!launchState.launchedWithAltTab && !scrollToFront) {
+                // Set the initial scroll to the predefined state (which differs from the stack)
+                float [] initialNormX = new float[] {
+                        getNormalizedXFromUnfocusedY(mSystemInsets.bottom + mInitialBottomOffset,
+                                FROM_BOTTOM),
+                        getNormalizedXFromUnfocusedY(mInitialTopOffset, FROM_TOP)
+                };
+
+                mUnfocusedRange.offset(0f);
+                List<Task> tasks = stack.getStackTasks();
+                int taskCount = tasks.size();
+                for (int i = taskCount - 1; i >= 0; i--) {
+                    int indexFromFront = taskCount - i - 1;
+                    if (indexFromFront >= initialNormX.length) {
+                        break;
+                    }
+                    float newTaskProgress = mInitialScrollP +
+                            mUnfocusedRange.getAbsoluteX(initialNormX[indexFromFront]);
+                    mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
+                }
             }
-            float newTaskProgress = mInitialScrollP +
-                    mUnfocusedRange.getAbsoluteX(mInitialNormX[indexFromFront]);
-            mTaskIndexOverrideMap.put(tasks.get(i).key.id, newTaskProgress);
         }
     }
 
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 0fc45ed..a75d1e1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,11 +28,9 @@
 import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
-import android.os.Parcelable;
 import android.provider.Settings;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -105,12 +103,6 @@
 
     private static final String TAG = "TaskStackView";
 
-    private final static String KEY_SAVED_STATE_SUPER = "saved_instance_state_super";
-    private final static String KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE =
-            "saved_instance_state_layout_focused_state";
-    private final static String KEY_SAVED_STATE_LAYOUT_STACK_SCROLL =
-            "saved_instance_state_layout_stack_scroll";
-
     // The thresholds at which to show/hide the stack action button.
     private static final float SHOW_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
     private static final float HIDE_STACK_ACTION_BUTTON_SCROLL_THRESHOLD = 0.3f;
@@ -350,11 +342,9 @@
     /**
      * Updates this TaskStackView to the initial state.
      */
-    public void updateToInitialState(boolean scrollToInitialState) {
-        if (scrollToInitialState) {
-            mStackScroller.setStackScrollToInitialState();
-        }
-        mLayoutAlgorithm.updateToInitialState(mStack.getStackTasks());
+    public void updateToInitialState() {
+        mStackScroller.setStackScrollToInitialState();
+        mLayoutAlgorithm.setTaskOverridesForInitialState(mStack);
     }
 
     /** Updates the list of task views */
@@ -638,18 +628,11 @@
     /**
      * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
      */
-    void relayoutTaskViews(AnimationProps animation) {
+    public void relayoutTaskViews(AnimationProps animation) {
         relayoutTaskViews(animation, mIgnoreTasks, false /* ignoreTaskOverrides */);
     }
 
     /**
-     * @see #relayoutTaskViews(AnimationProps, ArraySet<Task.TaskKey>, boolean)
-     */
-    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet) {
-        relayoutTaskViews(animation, ignoreTasksSet, false /* ignoreTaskOverrides */);
-    }
-
-    /**
      * Relayout the the visible {@link TaskView}s to their current transforms as specified by the
      * {@link TaskStackLayoutAlgorithm} with the given {@param animation}. This call cancels any
      * animations that are current running on those task views, and will ensure that the children
@@ -657,7 +640,7 @@
      *
      * @param ignoreTasksSet the set of tasks to ignore in the relayout
      */
-    void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
+    private void relayoutTaskViews(AnimationProps animation, ArraySet<Task.TaskKey> ignoreTasksSet,
             boolean ignoreTaskOverrides) {
         // If we had a deferred animation, cancel that
         mDeferredTaskViewLayoutAnimation = null;
@@ -841,7 +824,7 @@
      *
      * @param ignoreTasksSet the set of tasks to ignore in the relayout
      */
-    public void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
+    private void updateLayoutAlgorithm(boolean boundScrollToNewMinMax,
             ArraySet<Task.TaskKey> ignoreTasksSet) {
         // Compute the min and max scroll values
         mLayoutAlgorithm.update(mStack, ignoreTasksSet);
@@ -1098,24 +1081,6 @@
     }
 
     @Override
-    protected Parcelable onSaveInstanceState() {
-        Bundle savedState = new Bundle();
-        savedState.putParcelable(KEY_SAVED_STATE_SUPER, super.onSaveInstanceState());
-        savedState.putInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE, mLayoutAlgorithm.getFocusState());
-        savedState.putFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL, mStackScroller.getStackScroll());
-        return super.onSaveInstanceState();
-    }
-
-    @Override
-    protected void onRestoreInstanceState(Parcelable state) {
-        Bundle savedState = (Bundle) state;
-        super.onRestoreInstanceState(savedState.getParcelable(KEY_SAVED_STATE_SUPER));
-
-        mLayoutAlgorithm.setFocusState(savedState.getInt(KEY_SAVED_STATE_LAYOUT_FOCUSED_STATE));
-        mStackScroller.setStackScroll(savedState.getFloat(KEY_SAVED_STATE_LAYOUT_STACK_SCROLL));
-    }
-
-    @Override
     public CharSequence getAccessibilityClassName() {
         return TaskStackView.class.getName();
     }
@@ -1181,9 +1146,10 @@
      * Updates the system insets.
      */
     public void setSystemInsets(Rect systemInsets) {
-        if (!systemInsets.equals(mLayoutAlgorithm.mSystemInsets)) {
-            mStableLayoutAlgorithm.setSystemInsets(systemInsets);
-            mLayoutAlgorithm.setSystemInsets(systemInsets);
+        boolean changed = false;
+        changed |= mStableLayoutAlgorithm.setSystemInsets(systemInsets);
+        changed |= mLayoutAlgorithm.setSystemInsets(systemInsets);
+        if (changed) {
             requestLayout();
         }
     }
@@ -1215,13 +1181,17 @@
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
         mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
                 TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
-        updateLayoutAlgorithm(false /* boundScroll */, mIgnoreTasks);
+        updateLayoutAlgorithm(false /* boundScroll */);
 
         // If this is the first layout, then scroll to the front of the stack, then update the
         // TaskViews with the stack so that we can lay them out
         if (mAwaitingFirstLayout || mInitialState != INITIAL_STATE_UPDATE_NONE) {
-            updateToInitialState(mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY);
-            mInitialState = INITIAL_STATE_UPDATE_NONE;
+            if (mInitialState != INITIAL_STATE_UPDATE_LAYOUT_ONLY) {
+                updateToInitialState();
+            }
+            if (!mAwaitingFirstLayout) {
+                mInitialState = INITIAL_STATE_UPDATE_NONE;
+            }
         }
 
         // Rebind all the views, including the ignore ones
@@ -1245,16 +1215,16 @@
      * Measures a TaskView.
      */
     private void measureTaskView(TaskView tv) {
+        Rect padding = new Rect();
         if (tv.getBackground() != null) {
-            tv.getBackground().getPadding(mTmpRect);
-        } else {
-            mTmpRect.setEmpty();
+            tv.getBackground().getPadding(padding);
         }
-        Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+        mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
+        mTmpRect.union(mLayoutAlgorithm.mTaskRect);
         tv.measure(
-                MeasureSpec.makeMeasureSpec(taskRect.width() + mTmpRect.left + mTmpRect.right,
+                MeasureSpec.makeMeasureSpec(mTmpRect.width() + padding.left + padding.right,
                         MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(taskRect.height() + mTmpRect.top + mTmpRect.bottom,
+                MeasureSpec.makeMeasureSpec(mTmpRect.height() + padding.top + padding.bottom,
                         MeasureSpec.EXACTLY));
     }
 
@@ -1276,11 +1246,12 @@
         }
 
         // Relayout all of the task views including the ignored ones
-        relayoutTaskViews(AnimationProps.IMMEDIATE, mIgnoreTasks);
+        relayoutTaskViews(AnimationProps.IMMEDIATE);
         clipTaskViews();
 
         if (mAwaitingFirstLayout || !mEnterAnimationComplete) {
             mAwaitingFirstLayout = false;
+            mInitialState = INITIAL_STATE_UPDATE_NONE;
             onFirstLayout();
         }
     }
@@ -1290,15 +1261,15 @@
      */
     private void layoutTaskView(boolean changed, TaskView tv) {
         if (changed) {
+            Rect padding = new Rect();
             if (tv.getBackground() != null) {
-                tv.getBackground().getPadding(mTmpRect);
-            } else {
-                mTmpRect.setEmpty();
+                tv.getBackground().getPadding(padding);
             }
-            Rect taskRect = mStableLayoutAlgorithm.mTaskRect;
+            mTmpRect.set(mStableLayoutAlgorithm.mTaskRect);
+            mTmpRect.union(mLayoutAlgorithm.mTaskRect);
             tv.cancelTransformAnimation();
-            tv.layout(taskRect.left - mTmpRect.left, taskRect.top - mTmpRect.top,
-                    taskRect.right + mTmpRect.right, taskRect.bottom + mTmpRect.bottom);
+            tv.layout(mTmpRect.left - padding.left, mTmpRect.top - padding.top,
+                    mTmpRect.right + padding.right, mTmpRect.bottom + padding.bottom);
         } else {
             // If the layout has not changed, then just lay it out again in-place
             tv.layout(tv.getLeft(), tv.getTop(), tv.getRight(), tv.getBottom());
@@ -1836,9 +1807,17 @@
             // Calculate the new task stack bounds that matches the window size that Recents will
             // have after the drop
             final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget;
+            Rect systemInsets = new Rect(mStableLayoutAlgorithm.mSystemInsets);
+            // When docked, the nav bar insets are consumed and the activity is measured without
+            // insets.  However, the window bounds include the insets, so we need to subtract them
+            // here to make them identical.
+            int height = getMeasuredHeight();
+            height -= systemInsets.bottom;
+            systemInsets.bottom = 0;
             mStackBounds.set(dockState.getDockedTaskStackBounds(getMeasuredWidth(),
-                    getMeasuredHeight(), mDividerSize, mLayoutAlgorithm.mSystemInsets,
+                    height, mDividerSize, systemInsets,
                     mLayoutAlgorithm, getResources(), mWindowRect));
+            mLayoutAlgorithm.setSystemInsets(systemInsets);
             mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
             updateLayoutAlgorithm(true /* boundScroll */);
@@ -1849,6 +1828,7 @@
             mWindowRect.set(mStableWindowRect);
             mStackBounds.set(mStableStackBounds);
             removeIgnoreTask(event.task);
+            mLayoutAlgorithm.setSystemInsets(mStableLayoutAlgorithm.mSystemInsets);
             mLayoutAlgorithm.initialize(mWindowRect, mStackBounds,
                     TaskStackLayoutAlgorithm.StackState.getStackStateForStack(mStack));
             updateLayoutAlgorithm(true /* boundScroll */);
@@ -1970,25 +1950,31 @@
 
     public final void onBusEvent(MultiWindowStateChangedEvent event) {
         if (!event.inMultiWindow) {
-            // Scroll the stack to the front to see the undocked task
-            mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+            // Defer until the next frame to ensure that we have received all the system insets, and
+            // initial layout updates
+            post(new Runnable() {
                 @Override
                 public void run() {
-                    List<TaskView> taskViews = getTaskViews();
-                    int taskViewCount = taskViews.size();
-                    for (int i = 0; i < taskViewCount; i++) {
-                        TaskView tv = taskViews.get(i);
-                        tv.getHeaderView().rebindToTask(tv.getTask(), tv.mTouchExplorationEnabled,
-                                tv.mIsDisabledInSafeMode);
-                    }
+                    // Scroll the stack to the front to see the undocked task
+                    mStackScroller.animateScroll(mLayoutAlgorithm.mMaxScrollP, new Runnable() {
+                        @Override
+                        public void run() {
+                            List<TaskView> taskViews = getTaskViews();
+                            int taskViewCount = taskViews.size();
+                            for (int i = 0; i < taskViewCount; i++) {
+                                TaskView tv = taskViews.get(i);
+                                tv.getHeaderView().rebindToTask(tv.getTask(),
+                                        tv.mTouchExplorationEnabled, tv.mIsDisabledInSafeMode);
+                            }
+                        }
+                    });
                 }
             });
         }
     }
 
     public final void onBusEvent(ConfigurationChangedEvent event) {
-        mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
-        mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+        reloadOnConfigurationChange();
 
         // Notify the task views of the configuration change so they can reload their resources
         if (!event.fromMultiWindow) {
@@ -2003,11 +1989,17 @@
 
         // Trigger a new layout and update to the initial state if necessary
         if (event.fromMultiWindow) {
-            mInitialState = INITIAL_STATE_UPDATE_ALL;
-        } else if (event.fromOrientationChange) {
             mInitialState = INITIAL_STATE_UPDATE_LAYOUT_ONLY;
+            requestLayout();
+        } else if (event.fromDeviceOrientationChange) {
+            mInitialState = INITIAL_STATE_UPDATE_ALL;
+            requestLayout();
         }
-        requestLayout();
+    }
+
+    public void reloadOnConfigurationChange() {
+        mStableLayoutAlgorithm.reloadOnConfigurationChange(getContext());
+        mLayoutAlgorithm.reloadOnConfigurationChange(getContext());
     }
 
     /**
@@ -2096,7 +2088,7 @@
         if (mFocusedTask != null) {
             writer.print(innerPrefix);
             writer.print("Focused task: ");
-            mFocusedTask.dump(innerPrefix, writer);
+            mFocusedTask.dump("", writer);
         }
 
         mLayoutAlgorithm.dump(innerPrefix, writer);
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 6be8a4a..37f5a9f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -152,7 +152,6 @@
     private final TaskViewTransform mTargetAnimationTransform = new TaskViewTransform();
     private ArrayList<Animator> mTmpAnimators = new ArrayList<>();
 
-    View mContent;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="thumbnail_")
     TaskViewThumbnail mThumbnailView;
     @ViewDebug.ExportedProperty(deepExport=true, prefix="header_")
@@ -226,9 +225,9 @@
     @Override
     protected void onFinishInflate() {
         // Bind the views
-        mContent = findViewById(R.id.task_view_content);
         mHeaderView = (TaskViewHeader) findViewById(R.id.task_view_bar);
         mThumbnailView = (TaskViewThumbnail) findViewById(R.id.task_view_thumbnail);
+        mThumbnailView.updateClipToTaskBar(mHeaderView);
         mActionButtonView = findViewById(R.id.lock_to_app_fab);
         mActionButtonView.setOutlineProvider(new ViewOutlineProvider() {
             @Override
@@ -255,6 +254,9 @@
         if (w > 0 && h > 0) {
             mHeaderView.onTaskViewSizeChanged(w, h);
             mThumbnailView.onTaskViewSizeChanged(w, h);
+
+            mActionButtonView.setTranslationX(w - getMeasuredWidth());
+            mActionButtonView.setTranslationY(h - getMeasuredHeight());
         }
     }
 
@@ -276,13 +278,11 @@
     protected void measureContents(int width, int height) {
         int widthWithoutPadding = width - mPaddingLeft - mPaddingRight;
         int heightWithoutPadding = height - mPaddingTop - mPaddingBottom;
+        int widthSpec = MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY);
+        int heightSpec = MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY);
 
         // Measure the content
-        mContent.measure(MeasureSpec.makeMeasureSpec(widthWithoutPadding, MeasureSpec.EXACTLY),
-                MeasureSpec.makeMeasureSpec(heightWithoutPadding, MeasureSpec.EXACTLY));
-
-        // Optimization: Prevent overdraw of the thumbnail under the header view
-        mThumbnailView.updateClipToTaskBar(mHeaderView);
+        measureChildren(widthSpec, heightSpec);
 
         setMeasuredDimension(width, height);
     }
@@ -346,6 +346,8 @@
         mActionButtonView.setScaleX(1f);
         mActionButtonView.setScaleY(1f);
         mActionButtonView.setAlpha(0f);
+        mActionButtonView.setTranslationX(0f);
+        mActionButtonView.setTranslationY(0f);
         mActionButtonView.setTranslationZ(mActionButtonTranslationZ);
         if (mIncompatibleAppToastView != null) {
             mIncompatibleAppToastView.setVisibility(View.INVISIBLE);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index 16d8e53..fb0fc30 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -280,27 +280,31 @@
     /**
      * Update the header view when the configuration changes.
      */
-    void onConfigurationChanged() {
+    public void onConfigurationChanged() {
         // Update the dimensions of everything in the header. We do this because we need to use
         // resources for the display, and not the current configuration.
         Resources res = getResources();
-        mHeaderBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+        int headerBarHeight = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
                 R.dimen.recents_task_view_header_height,
                 R.dimen.recents_task_view_header_height,
                 R.dimen.recents_task_view_header_height,
                 R.dimen.recents_task_view_header_height_tablet_land,
                 R.dimen.recents_task_view_header_height,
                 R.dimen.recents_task_view_header_height_tablet_land);
-        mHeaderButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
+        int headerButtonPadding = TaskStackLayoutAlgorithm.getDimensionForDevice(res,
                 R.dimen.recents_task_view_header_button_padding,
                 R.dimen.recents_task_view_header_button_padding,
                 R.dimen.recents_task_view_header_button_padding,
                 R.dimen.recents_task_view_header_button_padding_tablet_land,
                 R.dimen.recents_task_view_header_button_padding,
                 R.dimen.recents_task_view_header_button_padding_tablet_land);
-        updateLayoutParams(mIconView, mTitleView, mMoveTaskButton, mDismissButton);
-        if (mAppOverlayView != null) {
-            updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+        if (headerBarHeight != mHeaderBarHeight || headerButtonPadding != mHeaderButtonPadding) {
+            mHeaderBarHeight = headerBarHeight;
+            mHeaderButtonPadding = headerButtonPadding;
+            updateLayoutParams(mIconView, mTitleView, mMoveTaskButton, mDismissButton);
+            if (mAppOverlayView != null) {
+                updateLayoutParams(mAppIconView, mAppTitleView, null, mAppInfoView);
+            }
         }
     }
 
@@ -346,6 +350,8 @@
         }
         mDismissButton.setVisibility(showDismissIcon ? View.VISIBLE : View.INVISIBLE);
         mDismissButton.setTranslationX(rightInset);
+
+        setLeftTopRightBottom(0, 0, width, getMeasuredHeight());
     }
 
     @Override
@@ -434,7 +440,6 @@
 
     /** Binds the bar view to the task */
     public void rebindToTask(Task t, boolean touchExplorationEnabled, boolean disabledInSafeMode) {
-        SystemServicesProxy ssp = Recents.getSystemServices();
         mTask = t;
 
         // If an activity icon is defined, then we use that as the primary icon to show in the bar,
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 62fd585..4de7713 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewThumbnail.java
@@ -123,6 +123,7 @@
         }
 
         mTaskViewRect.set(0, 0, width, height);
+        setLeftTopRightBottom(0, 0, width, height);
         updateThumbnailScale();
     }
 
@@ -148,22 +149,26 @@
         int thumbnailHeight = Math.min(viewHeight,
                 (int) (mThumbnailRect.height() * mThumbnailScale));
         if (mBitmapShader != null && thumbnailWidth > 0 && thumbnailHeight > 0) {
+            int topOffset = mTaskBar != null
+                    ? mTaskBar.getHeight() - mCornerRadius
+                    : 0;
+
             // Draw the background, there will be some small overdraw with the thumbnail
             if (thumbnailWidth < viewWidth) {
                 // Portrait thumbnail on a landscape task view
-                canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), 0,
+                canvas.drawRoundRect(Math.max(0, thumbnailWidth - mCornerRadius), topOffset,
                         viewWidth, viewHeight,
                         mCornerRadius, mCornerRadius, mBgFillPaint);
             }
             if (thumbnailHeight < viewHeight) {
                 // Landscape thumbnail on a portrait task view
-                canvas.drawRoundRect(0, Math.max(0, thumbnailHeight - mCornerRadius),
+                canvas.drawRoundRect(0, Math.max(topOffset, thumbnailHeight - mCornerRadius),
                         viewWidth, viewHeight,
                         mCornerRadius, mCornerRadius, mBgFillPaint);
             }
 
             // Draw the thumbnail
-            canvas.drawRoundRect(0, 0, thumbnailWidth, thumbnailHeight,
+            canvas.drawRoundRect(0, topOffset, thumbnailWidth, thumbnailHeight,
                     mCornerRadius, mCornerRadius, mDrawPaint);
         } else {
             canvas.drawRoundRect(0, 0, viewWidth, viewHeight, mCornerRadius, mCornerRadius,
@@ -274,10 +279,7 @@
     /** Updates the clip rect based on the given task bar. */
     void updateClipToTaskBar(View taskBar) {
         mTaskBar = taskBar;
-        int top = (int) Math.max(0, taskBar.getTranslationY() +
-                taskBar.getMeasuredHeight() - 1);
-        mClipRect.set(0, top, getMeasuredWidth(), getMeasuredHeight());
-        setClipBounds(mClipRect);
+        invalidate();
     }
 
     /** Updates the visibility of the the thumbnail. */
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
index b512393..397f24e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewTransform.java
@@ -19,11 +19,14 @@
 import android.animation.Animator;
 import android.animation.ObjectAnimator;
 import android.animation.PropertyValuesHolder;
+import android.graphics.Rect;
 import android.graphics.RectF;
 import android.util.IntProperty;
 import android.util.Property;
 import android.view.View;
 
+import com.android.systemui.recents.misc.Utilities;
+
 import java.util.ArrayList;
 
 /**
@@ -31,55 +34,20 @@
  */
 public class TaskViewTransform {
 
-    public static final Property<View, Integer> LEFT =
-            new IntProperty<View>("left") {
+    public static final Property<View, Rect> LTRB =
+            new Property<View, Rect>(Rect.class, "leftTopRightBottom") {
+
+                private Rect mTmpRect = new Rect();
+
                 @Override
-                public void setValue(View object, int v) {
-                    object.setLeft(v);
+                public void set(View v, Rect ltrb) {
+                    v.setLeftTopRightBottom(ltrb.left, ltrb.top, ltrb.right, ltrb.bottom);
                 }
 
                 @Override
-                public Integer get(View object) {
-                    return object.getLeft();
-                }
-            };
-
-    public static final Property<View, Integer> TOP =
-            new IntProperty<View>("top") {
-                @Override
-                public void setValue(View object, int v) {
-                    object.setTop(v);
-                }
-
-                @Override
-                public Integer get(View object) {
-                    return object.getTop();
-                }
-            };
-
-    public static final Property<View, Integer> RIGHT =
-            new IntProperty<View>("right") {
-                @Override
-                public void setValue(View object, int v) {
-                    object.setRight(v);
-                }
-
-                @Override
-                public Integer get(View object) {
-                    return object.getRight();
-                }
-            };
-
-    public static final Property<View, Integer> BOTTOM =
-            new IntProperty<View>("bottom") {
-                @Override
-                public void setValue(View object, int v) {
-                    object.setBottom(v);
-                }
-
-                @Override
-                public Integer get(View object) {
-                    return object.getBottom();
+                public Rect get(View v) {
+                    mTmpRect.set(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+                    return mTmpRect;
                 }
             };
 
@@ -205,11 +173,12 @@
                 animators.add(animation.apply(AnimationProps.ALPHA, anim));
             }
             if (hasRectChangedFrom(v)) {
+                Rect fromViewRect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
+                Rect toViewRect = new Rect();
+                rect.round(toViewRect);
                 ObjectAnimator anim = ObjectAnimator.ofPropertyValuesHolder(v,
-                        PropertyValuesHolder.ofInt(LEFT, v.getLeft(), (int) rect.left),
-                        PropertyValuesHolder.ofInt(TOP, v.getTop(), (int) rect.top),
-                        PropertyValuesHolder.ofInt(RIGHT, v.getRight(), (int) rect.right),
-                        PropertyValuesHolder.ofInt(BOTTOM, v.getBottom(), (int) rect.bottom));
+                        PropertyValuesHolder.ofObject(LTRB, Utilities.RECT_EVALUATOR,
+                                fromViewRect, toViewRect));
                 animators.add(animation.apply(AnimationProps.BOUNDS, anim));
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index a6c75e8..66a413c 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -332,13 +332,18 @@
 
     public void stopDragging(int position, SnapTarget target, long duration,
             Interpolator interpolator) {
-        stopDragging(position, target, duration, 0 /* startDelay*/, interpolator);
+        stopDragging(position, target, duration, 0 /* startDelay*/, 0 /* endDelay */, interpolator);
+    }
+
+    public void stopDragging(int position, SnapTarget target, long duration,
+            Interpolator interpolator, long endDelay) {
+        stopDragging(position, target, duration, 0 /* startDelay*/, endDelay, interpolator);
     }
 
     public void stopDragging(int position, SnapTarget target, long duration, long startDelay,
-            Interpolator interpolator) {
+            long endDelay, Interpolator interpolator) {
         mHandle.setTouching(false, true /* animate */);
-        flingTo(position, target, duration, startDelay, interpolator);
+        flingTo(position, target, duration, startDelay, endDelay, interpolator);
         mWindowManager.setSlippery(true);
         releaseBackground();
     }
@@ -471,21 +476,22 @@
         if (logMetrics) {
             logResizeEvent(snapTarget);
         }
-        ValueAnimator anim = getFlingAnimator(position, snapTarget);
+        ValueAnimator anim = getFlingAnimator(position, snapTarget, 0 /* endDelay */);
         mFlingAnimationUtils.apply(anim, position, snapTarget.position, velocity);
         anim.start();
     }
 
     private void flingTo(int position, SnapTarget target, long duration, long startDelay,
-            Interpolator interpolator) {
-        ValueAnimator anim = getFlingAnimator(position, target);
+            long endDelay, Interpolator interpolator) {
+        ValueAnimator anim = getFlingAnimator(position, target, endDelay);
         anim.setDuration(duration);
         anim.setStartDelay(startDelay);
         anim.setInterpolator(interpolator);
         anim.start();
     }
 
-    private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget) {
+    private ValueAnimator getFlingAnimator(int position, final SnapTarget snapTarget,
+            final long endDelay) {
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
@@ -496,16 +502,31 @@
                                 : snapTarget.position, snapTarget);
             }
         });
+        Runnable endAction = () -> {
+            commitSnapFlags(snapTarget);
+            mWindowManagerProxy.setResizing(false);
+            mDockSide = WindowManager.DOCKED_INVALID;
+            mCurrentAnimator = null;
+            mEntranceAnimationRunning = false;
+            mExitAnimationRunning = false;
+            EventBus.getDefault().send(new StoppedDragingEvent());
+        };
         anim.addListener(new AnimatorListenerAdapter() {
+
+            private boolean mCancelled;
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+                mCancelled = true;
+            }
+
             @Override
             public void onAnimationEnd(Animator animation) {
-                commitSnapFlags(snapTarget);
-                mWindowManagerProxy.setResizing(false);
-                mDockSide = WindowManager.DOCKED_INVALID;
-                mCurrentAnimator = null;
-                mEntranceAnimationRunning = false;
-                mExitAnimationRunning = false;
-                EventBus.getDefault().send(new StoppedDragingEvent());
+                if (endDelay == 0 || mCancelled) {
+                    endAction.run();
+                } else {
+                    postDelayed(endAction, endDelay);
+                }
             }
         });
         mCurrentAnimator = anim;
@@ -733,8 +754,10 @@
                     mDockSide, mDockedTaskRect);
             calculateBoundsForPosition(mExitStartPosition,
                     DockedDividerUtils.invertDockSide(mDockSide), mOtherTaskRect);
+            mOtherInsetRect.set(mOtherTaskRect);
+            applyExitAnimationParallax(mOtherTaskRect, position);
             mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, null,
-                    mOtherTaskRect, null);
+                    mOtherTaskRect, mOtherInsetRect);
         } else if (taskPosition != TASK_POSITION_SAME) {
             calculateBoundsForPosition(position, DockedDividerUtils.invertDockSide(mDockSide),
                     mOtherRect);
@@ -773,6 +796,16 @@
                 dimFraction);
     }
 
+    private void applyExitAnimationParallax(Rect taskRect, int position) {
+        if (mDockSide == WindowManager.DOCKED_TOP) {
+            taskRect.offset(0, (int) ((position - mExitStartPosition) * 0.25f));
+        } else if (mDockSide == WindowManager.DOCKED_LEFT) {
+            taskRect.offset((int) ((position - mExitStartPosition) * 0.25f), 0);
+        } else if (mDockSide == WindowManager.DOCKED_RIGHT) {
+            taskRect.offset((int) ((mExitStartPosition - position) * 0.25f), 0);
+        }
+    }
+
     private float getDimFraction(int position, SnapTarget dismissTarget) {
         if (mEntranceAnimationRunning) {
             return 0f;
@@ -956,14 +989,17 @@
         if (mAnimateAfterRecentsDrawn) {
             mAnimateAfterRecentsDrawn = false;
             updateDockSide();
-            stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
-                    Interpolators.TOUCH_RESPONSE);
+
+            // Delay switching resizing mode because this might cause jank in recents animation
+            // that's long than this animation.
+            stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(),
+                    250 /* startDelay */, Interpolators.FAST_OUT_SLOW_IN, 200 /* endDelay */);
         }
         if (mGrowAfterRecentsDrawn) {
             mGrowAfterRecentsDrawn = false;
             updateDockSide();
             stopDragging(getCurrentPosition(), mSnapAlgorithm.getMiddleTarget(), 250,
-                    Interpolators.TOUCH_RESPONSE);
+                    Interpolators.FAST_OUT_SLOW_IN);
         }
     }
 
@@ -979,7 +1015,7 @@
             mExitAnimationRunning = true;
             mExitStartPosition = getCurrentPosition();
             stopDragging(mExitStartPosition, target, 336 /* duration */, 100 /* startDelay */,
-                    Interpolators.TOUCH_RESPONSE);
+                    0 /* endDelay */, Interpolators.FAST_OUT_SLOW_IN);
 
             // Vibrate after undocking
             performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 11a7048..237ca5e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -1341,7 +1341,7 @@
     }
 
     protected void toggleKeyboardShortcuts(int deviceId) {
-        getKeyboardShortcuts().toggleKeyboardShortcuts(deviceId);
+        KeyboardShortcuts.toggle(mContext, deviceId);
     }
 
     protected void cancelPreloadingRecents() {
@@ -1575,7 +1575,11 @@
             row.setRemoteInputController(mRemoteInputController);
             row.setOnExpandClickListener(this);
 
-            // Get the app name
+            // Get the app name.
+            // Note that Notification.Builder#bindHeaderAppName has similar logic
+            // but since this field is used in the guts, it must be accurate.
+            // Therefore we will only show the application label, or, failing that, the
+            // package name. No substitutions.
             final String pkg = sbn.getPackageName();
             String appname = pkg;
             try {
@@ -1738,14 +1742,6 @@
         }
     }
 
-    protected KeyboardShortcuts getKeyboardShortcuts() {
-        if (mKeyboardShortcuts == null) {
-            mKeyboardShortcuts = new KeyboardShortcuts(mContext);
-        }
-
-        return mKeyboardShortcuts;
-    }
-
     public void startPendingIntentDismissingKeyguard(final PendingIntent intent) {
         if (!isDeviceProvisioned()) return;
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
index c2521b3..79e06c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcuts.java
@@ -70,6 +70,10 @@
  */
 public final class KeyboardShortcuts {
     private static final String TAG = KeyboardShortcuts.class.getSimpleName();
+    private static final Object sLock = new Object();
+    private static KeyboardShortcuts sInstance;
+    private static boolean sIsShowing;
+
     private final SparseArray<String> mSpecialCharacterNames = new SparseArray<>();
     private final SparseArray<String> mModifierNames = new SparseArray<>();
     private final SparseArray<Drawable> mSpecialCharacterDrawables = new SparseArray<>();
@@ -80,7 +84,7 @@
     private final IPackageManager mPackageManager;
     private final OnClickListener mDialogCloseListener = new DialogInterface.OnClickListener() {
         public void onClick(DialogInterface dialog, int id) {
-            dismissKeyboardShortcutsDialog();
+            dismissKeyboardShortcuts();
         }
     };
     private final Comparator<KeyboardShortcutInfo> mApplicationItemsComparator =
@@ -108,12 +112,49 @@
     private Dialog mKeyboardShortcutsDialog;
     private KeyCharacterMap mKeyCharacterMap;
 
-    public KeyboardShortcuts(Context context) {
+    private KeyboardShortcuts(Context context) {
         this.mContext = new ContextThemeWrapper(context, android.R.style.Theme_Material_Light);
         this.mPackageManager = AppGlobals.getPackageManager();
         loadResources(context);
     }
 
+    private static KeyboardShortcuts getInstance(Context context) {
+        if (sInstance == null) {
+            sInstance = new KeyboardShortcuts(context);
+        }
+        return sInstance;
+    }
+
+    public static void show(Context context, int deviceId) {
+        synchronized (sLock) {
+            if (sInstance != null && !sInstance.mContext.equals(context)) {
+                dismiss();
+            }
+            getInstance(context).showKeyboardShortcuts(deviceId);
+            sIsShowing = true;
+        }
+    }
+
+    public static void toggle(Context context, int deviceId) {
+        synchronized (sLock) {
+            if (sIsShowing) {
+                dismiss();
+            } else {
+                show(context, deviceId);
+            }
+        }
+    }
+
+    public static void dismiss() {
+        synchronized (sLock) {
+            if (sInstance != null) {
+                sInstance.dismissKeyboardShortcuts();
+                sInstance = null;
+            }
+            sIsShowing = false;
+        }
+    }
+
     private void loadResources(Context context) {
         mSpecialCharacterNames.put(
                 KeyEvent.KEYCODE_HOME, context.getString(R.string.keyboard_key_home));
@@ -277,27 +318,6 @@
                 KeyEvent.META_META_ON, context.getDrawable(R.drawable.ic_ksh_key_meta));
     }
 
-    public void toggleKeyboardShortcuts(int deviceId) {
-        retrieveKeyCharacterMap(deviceId);
-        if (mKeyboardShortcutsDialog == null) {
-            Recents.getSystemServices().requestKeyboardShortcuts(mContext,
-                new KeyboardShortcutsReceiver() {
-                    @Override
-                    public void onKeyboardShortcutsReceived(
-                            final List<KeyboardShortcutGroup> result) {
-                        result.add(getSystemShortcuts());
-                        final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
-                        if (appShortcuts != null) {
-                            result.add(appShortcuts);
-                        }
-                        showKeyboardShortcutsDialog(result);
-                    }
-                }, deviceId);
-        } else {
-            dismissKeyboardShortcutsDialog();
-        }
-    }
-
     /**
      * Retrieves a {@link KeyCharacterMap} and assigns it to mKeyCharacterMap. If the given id is an
      * existing device, that device's map is used. Otherwise, it checks first all available devices
@@ -327,7 +347,24 @@
         mKeyCharacterMap = inputDevice.getKeyCharacterMap();
     }
 
-    public void dismissKeyboardShortcutsDialog() {
+    private void showKeyboardShortcuts(int deviceId) {
+        retrieveKeyCharacterMap(deviceId);
+        Recents.getSystemServices().requestKeyboardShortcuts(mContext,
+                new KeyboardShortcutsReceiver() {
+                    @Override
+                    public void onKeyboardShortcutsReceived(
+                            final List<KeyboardShortcutGroup> result) {
+                        result.add(getSystemShortcuts());
+                        final KeyboardShortcutGroup appShortcuts = getDefaultApplicationShortcuts();
+                        if (appShortcuts != null) {
+                            result.add(appShortcuts);
+                        }
+                        showKeyboardShortcutsDialog(result);
+                    }
+                }, deviceId);
+    }
+
+    private void dismissKeyboardShortcuts() {
         if (mKeyboardShortcutsDialog != null) {
             mKeyboardShortcutsDialog.dismiss();
             mKeyboardShortcutsDialog = null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
index 5d22faf..5f4ebd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutsReceiver.java
@@ -26,8 +26,7 @@
     @Override
     public void onReceive(Context context, Intent intent) {
         if (Intent.ACTION_SHOW_KEYBOARD_SHORTCUTS.equals(intent.getAction())) {
-            final KeyboardShortcuts keyboardShortcuts = new KeyboardShortcuts(context);
-            keyboardShortcuts.toggleKeyboardShortcuts(-1 /* deviceId unknown */);
+            KeyboardShortcuts.show(context, -1 /* deviceId unknown */);
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 7fbb176..74bd096 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -30,6 +30,7 @@
 import com.android.systemui.BatteryMeterView;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.qs.QSPanel;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.KeyguardUserSwitcher;
 import com.android.systemui.statusbar.policy.UserInfoController;
@@ -150,6 +151,10 @@
         });
     }
 
+    public void setQSPanel(QSPanel qsp) {
+        mMultiUserSwitch.setQsPanel(qsp);
+    }
+
     @Override
     public void onBatteryLevelChanged(int level, boolean pluggedIn, boolean charging) {
         String percentage = NumberFormat.getPercentInstance().format((double) level / 100.0);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
index 54af684..6698d13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/MultiUserSwitch.java
@@ -127,10 +127,10 @@
                         mTmpInt2);
             }
         } else {
-            Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
-                    getContext(), v, ContactsContract.Profile.CONTENT_URI,
-                    ContactsContract.QuickContact.MODE_LARGE, null);
             if (mQsPanel != null) {
+                Intent intent = ContactsContract.QuickContact.composeQuickContactsIntent(
+                        getContext(), v, ContactsContract.Profile.CONTENT_URI,
+                        ContactsContract.QuickContact.MODE_LARGE, null);
                 mQsPanel.getHost().startActivityDismissingKeyguard(intent);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 5423f9d..3ca0a6d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -133,6 +133,7 @@
 import com.android.systemui.statusbar.EmptyShadeView;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
 import com.android.systemui.statusbar.GestureRecorder;
+import com.android.systemui.statusbar.KeyboardShortcuts;
 import com.android.systemui.statusbar.KeyguardIndicationController;
 import com.android.systemui.statusbar.NotificationData;
 import com.android.systemui.statusbar.NotificationData.Entry;
@@ -893,6 +894,7 @@
                     qsContainer.setHost(qsh);
                     mQSPanel = qsContainer.getQsPanel();
                     mQSPanel.setBrightnessMirror(mBrightnessMirrorController);
+                    mKeyguardStatusBar.setQSPanel(mQSPanel);
                     mHeader = qsContainer.getHeader();
                     initSignalCluster(mHeader);
                     mHeader.setActivityStarter(PhoneStatusBar.this);
@@ -3160,7 +3162,7 @@
             if (DEBUG) Log.v(TAG, "onReceive: " + intent);
             String action = intent.getAction();
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(action)) {
-                getKeyboardShortcuts().dismissKeyboardShortcutsDialog();
+                KeyboardShortcuts.dismiss();
                 if (isCurrentProfile(getSendingUserId())) {
                     int flags = CommandQueue.FLAG_EXCLUDE_NONE;
                     String reason = intent.getStringExtra("reason");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
index ebefdde..52fb470 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/HeadsUpManager.java
@@ -674,6 +674,13 @@
             } else if (!selfFullscreen && otherFullscreen) {
                 return 1;
             }
+
+            if (remoteInputActive && !o.remoteInputActive) {
+                return -1;
+            } else if (!remoteInputActive && o.remoteInputActive) {
+                return 1;
+            }
+
             return postTime < o.postTime ? 1
                     : postTime == o.postTime ? entry.key.compareTo(o.entry.key)
                             : -1;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
new file mode 100644
index 0000000..c65415e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlButtonView.java
@@ -0,0 +1,142 @@
+/*
+ * 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.systemui.tv.pip;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.LayoutInflater;
+import android.view.View.OnFocusChangeListener;
+import android.view.View;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+
+import com.android.systemui.R;
+
+/**
+ * A view containing PIP controls including fullscreen, close, and media controls.
+ */
+public class PipControlButtonView extends LinearLayout {
+    private OnFocusChangeListener mFocusChangeListener;
+    private ImageView mButtonImageView;
+    private TextView mDescriptionTextView;
+    private Animator mFocusGainAnimator;
+    private Animator mFocusLoseAnimator;
+
+    private final OnFocusChangeListener mInternalFocusChangeListener =
+            new OnFocusChangeListener() {
+                @Override
+                public void onFocusChange(View v, boolean hasFocus) {
+                    if (hasFocus) {
+                        if (mFocusLoseAnimator.isStarted()) {
+                            mFocusLoseAnimator.cancel();
+                        }
+                        mFocusGainAnimator.start();
+                    } else {
+                        if (mFocusGainAnimator.isStarted()) {
+                            mFocusGainAnimator.cancel();
+                        }
+                        mFocusLoseAnimator.start();
+                    }
+
+                    if (mFocusChangeListener != null) {
+                        mFocusChangeListener.onFocusChange(v, hasFocus);
+                    }
+                }
+            };
+
+    public PipControlButtonView(Context context) {
+        this(context, null, 0, 0);
+    }
+
+    public PipControlButtonView(Context context, AttributeSet attrs) {
+        this(context, attrs, 0, 0);
+    }
+
+    public PipControlButtonView(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public PipControlButtonView(
+            Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+        LayoutInflater inflater = (LayoutInflater) getContext()
+                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+        inflater.inflate(R.layout.tv_pip_control_button, this);
+
+        setOrientation(LinearLayout.VERTICAL);
+        setGravity(Gravity.CENTER);
+
+        mButtonImageView = (ImageView) findViewById(R.id.button);
+        mDescriptionTextView = (TextView) findViewById(R.id.desc);
+
+        int[] values = new int[] {android.R.attr.src, android.R.attr.text};
+        TypedArray typedArray =
+            context.obtainStyledAttributes(attrs, values, defStyleAttr, defStyleRes);
+
+        mButtonImageView.setImageDrawable(typedArray.getDrawable(0));
+        mDescriptionTextView.setText(typedArray.getText(1));
+
+        typedArray.recycle();
+    }
+
+    @Override
+    public void onFinishInflate() {
+        super.onFinishInflate();
+        mButtonImageView.setOnFocusChangeListener(mInternalFocusChangeListener);
+
+        mFocusGainAnimator = AnimatorInflater.loadAnimator(getContext(),
+                R.anim.tv_pip_controls_text_focus_gain_animation);
+        mFocusGainAnimator.setTarget(mDescriptionTextView);
+        mFocusLoseAnimator = AnimatorInflater.loadAnimator(getContext(),
+                R.anim.tv_pip_controls_text_focus_lose_animation);
+        mFocusLoseAnimator.setTarget(mDescriptionTextView);
+    }
+
+    @Override
+    public void setOnClickListener(OnClickListener listener) {
+        mButtonImageView.setOnClickListener(listener);
+    }
+
+    @Override
+    public void setOnFocusChangeListener(OnFocusChangeListener listener) {
+        mFocusChangeListener = listener;
+    }
+
+    /**
+     * Sets the drawable for the button with the given resource id.
+     */
+    public void setImageResource(int resId) {
+        mButtonImageView.setImageResource(resId);
+    }
+
+    /**
+     * Sets the text for description the with the given resource id.
+     */
+    public void setText(int resId) {
+        mDescriptionTextView.setText(resId);
+    }
+
+    @Override
+    public boolean isFocused() {
+        return mButtonImageView.isFocused();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
index 3f87611..d15799c 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipControlsView.java
@@ -57,13 +57,9 @@
     final PipManager mPipManager = PipManager.getInstance();
     Listener mListener;
 
-    View mFullButtonView;
-    View mFullDescriptionView;
-    View mPlayPauseView;
-    ImageView mPlayPauseButtonImageView;
-    TextView mPlayPauseDescriptionTextView;
-    View mCloseButtonView;
-    View mCloseDescriptionView;
+    PipControlButtonView mFullButtonView;
+    PipControlButtonView mCloseButtonView;
+    PipControlButtonView mPlayPauseButtonView;
 
     private boolean mHasFocus;
     private OnFocusChangeListener mOnChildFocusChangeListener;
@@ -75,13 +71,20 @@
         }
     };
 
-    private PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
+    private final PipManager.MediaListener mPipMediaListener = new PipManager.MediaListener() {
         @Override
         public void onMediaControllerChanged() {
             updateMediaController();
         }
     };
 
+    private final OnFocusChangeListener mFocusChangeListener = new OnFocusChangeListener() {
+        @Override
+        public void onFocusChange(View v, boolean hasFocus) {
+            onChildViewFocusChanged();
+        }
+    };
+
     public PipControlsView(Context context) {
         this(context, null, 0, 0);
     }
@@ -108,26 +111,30 @@
     public void onFinishInflate() {
         super.onFinishInflate();
 
-        mFullButtonView = findViewById(R.id.full_button);
-        mFullDescriptionView = findViewById(R.id.full_desc);
+        mFullButtonView = (PipControlButtonView) findViewById(R.id.full_button);
+        mFullButtonView.setOnFocusChangeListener(mFocusChangeListener);
         mFullButtonView.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 mPipManager.movePipToFullscreen();
             }
         });
-        mFullButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
+
+        mCloseButtonView = (PipControlButtonView) findViewById(R.id.close_button);
+        mCloseButtonView.setOnFocusChangeListener(mFocusChangeListener);
+        mCloseButtonView.setOnClickListener(new View.OnClickListener() {
             @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                mFullDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
-                onChildViewFocusChanged();
+            public void onClick(View v) {
+                mPipManager.closePip();
+                if (mListener != null) {
+                    mListener.onClosed();
+                }
             }
         });
 
-        mPlayPauseView = findViewById(R.id.play_pause);
-        mPlayPauseButtonImageView = (ImageView) findViewById(R.id.play_pause_button);
-        mPlayPauseDescriptionTextView = (TextView) findViewById(R.id.play_pause_desc);
-        mPlayPauseButtonImageView.setOnClickListener(new View.OnClickListener() {
+        mPlayPauseButtonView = (PipControlButtonView) findViewById(R.id.play_pause_button);
+        mPlayPauseButtonView.setOnFocusChangeListener(mFocusChangeListener);
+        mPlayPauseButtonView.setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 if (mMediaController == null || mMediaController.getPlaybackState() == null) {
@@ -143,33 +150,6 @@
                 // View will be updated later in {@link mMediaControllerCallback}
             }
         });
-        mPlayPauseButtonImageView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                mPlayPauseDescriptionTextView.setVisibility(
-                        hasFocus ? View.VISIBLE : View.INVISIBLE);
-                onChildViewFocusChanged();
-            }
-        });
-
-        mCloseButtonView = findViewById(R.id.close_button);
-        mCloseDescriptionView = findViewById(R.id.close_desc);
-        mCloseButtonView.setOnClickListener(new View.OnClickListener() {
-            @Override
-            public void onClick(View v) {
-                mPipManager.closePip();
-                if (mListener != null) {
-                    mListener.onClosed();
-                }
-            }
-        });
-        mCloseButtonView.setOnFocusChangeListener(new View.OnFocusChangeListener() {
-            @Override
-            public void onFocusChange(View v, boolean hasFocus) {
-                mCloseDescriptionView.setVisibility(hasFocus ? View.VISIBLE : View.INVISIBLE);
-                onChildViewFocusChanged();
-            }
-        });
     }
 
     @Override
@@ -206,15 +186,15 @@
     private void updatePlayPauseView() {
         int state = mPipManager.getPlaybackState();
         if (state == PLAYBACK_STATE_UNAVAILABLE) {
-            mPlayPauseView.setVisibility(View.GONE);
+            mPlayPauseButtonView.setVisibility(View.GONE);
         } else {
-            mPlayPauseView.setVisibility(View.VISIBLE);
+            mPlayPauseButtonView.setVisibility(View.VISIBLE);
             if (state == PLAYBACK_STATE_PLAYING) {
-                mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_pause_button);
-                mPlayPauseDescriptionTextView.setText(R.string.pip_pause);
+                mPlayPauseButtonView.setImageResource(R.drawable.ic_pause_white_24dp);
+                mPlayPauseButtonView.setText(R.string.pip_pause);
             } else {
-                mPlayPauseButtonImageView.setImageResource(R.drawable.tv_pip_play_button);
-                mPlayPauseDescriptionTextView.setText(R.string.pip_play);
+                mPlayPauseButtonView.setImageResource(R.drawable.ic_play_arrow_white_24dp);
+                mPlayPauseButtonView.setText(R.string.pip_play);
             }
         }
     }
@@ -229,7 +209,7 @@
     private void onChildViewFocusChanged() {
         // At this moment, hasFocus() returns true although there's no focused child.
         boolean hasFocus = (mFullButtonView != null && mFullButtonView.isFocused())
-                || (mPlayPauseButtonImageView != null && mPlayPauseButtonImageView.isFocused())
+                || (mPlayPauseButtonView != null && mPlayPauseButtonView.isFocused())
                 || (mCloseButtonView != null && mCloseButtonView.isFocused());
         if (mHasFocus != hasFocus) {
             mHasFocus = hasFocus;
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
index 854e09d..542a935 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipMenuActivity.java
@@ -16,10 +16,14 @@
 
 package com.android.systemui.tv.pip;
 
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
 import android.app.Activity;
 import android.os.Bundle;
+import android.view.View;
 
 import com.android.systemui.R;
+import com.android.systemui.Interpolators;
 
 /**
  * Activity to show the PIP menu to control PIP.
@@ -29,7 +33,9 @@
 
     private final PipManager mPipManager = PipManager.getInstance();
 
-    private PipControlsView mPipControlsView;
+    private Animator mFadeInAnimation;
+    private Animator mFadeOutAnimation;
+    private View mPipControlsView;
     private boolean mRestorePipSizeWhenClose;
 
     @Override
@@ -38,8 +44,14 @@
         setContentView(R.layout.tv_pip_menu);
         mPipManager.addListener(this);
 
-        mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
         mRestorePipSizeWhenClose = true;
+        mPipControlsView = (PipControlsView) findViewById(R.id.pip_controls);
+        mFadeInAnimation = AnimatorInflater.loadAnimator(
+                this, R.anim.tv_pip_menu_fade_in_animation);
+        mFadeInAnimation.setTarget(mPipControlsView);
+        mFadeOutAnimation = AnimatorInflater.loadAnimator(
+                this, R.anim.tv_pip_menu_fade_out_animation);
+        mFadeOutAnimation.setTarget(mPipControlsView);
     }
 
     private void restorePipAndFinish() {
@@ -51,8 +63,15 @@
     }
 
     @Override
+    public void onResume() {
+        super.onResume();
+        mFadeInAnimation.start();
+    }
+
+    @Override
     public void onPause() {
         super.onPause();
+        mFadeOutAnimation.start();
         restorePipAndFinish();
     }
 
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 86ceff4..398572a 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipOnboardingActivity.java
@@ -16,12 +16,15 @@
 
 package com.android.systemui.tv.pip;
 
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
 import android.app.Activity;
-import android.graphics.Rect;
+import android.graphics.drawable.AnimationDrawable;
 import android.os.Bundle;
-import android.util.Log;
 import android.view.View;
-import android.view.ViewGroup.LayoutParams;
+import android.widget.ImageView;
 
 import com.android.systemui.R;
 
@@ -35,29 +38,47 @@
     protected void onCreate(Bundle bundle) {
         super.onCreate(bundle);
         setContentView(R.layout.tv_pip_onboarding);
-        View pipOnboardingView = findViewById(R.id.pip_onboarding);
-        View pipOutlineView = findViewById(R.id.pip_outline);
-        mPipManager.addListener(this);
-        findViewById(R.id.close).setOnClickListener(new View.OnClickListener() {
+        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
             @Override
             public void onClick(View v) {
                 finish();
             }
         });
 
-        int pipOutlineSpace = getResources().getDimensionPixelSize(R.dimen.tv_pip_bounds_space);
-        int screenWidth = getResources().getDisplayMetrics().widthPixels;
-        Rect pipBounds = mPipManager.getPipBounds();
-        pipOnboardingView.setPadding(
-                pipBounds.left - pipOutlineSpace,
-                pipBounds.top - pipOutlineSpace,
-                screenWidth - pipBounds.right - pipOutlineSpace, 0);
+        mPipManager.addListener(this);
+    }
 
-        // Set width and height for outline view to enclose the PIP.
-        LayoutParams lp = pipOutlineView.getLayoutParams();
-        lp.width = pipBounds.width() + pipOutlineSpace * 2;
-        lp.height = pipBounds.height() + pipOutlineSpace * 2;
-        pipOutlineView.setLayoutParams(lp);
+    @Override
+    public void onResume() {
+        super.onResume();
+        AnimatorSet enterAnimator = new AnimatorSet();
+        enterAnimator.playTogether(
+                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() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+                ImageView button = (ImageView) findViewById(R.id.remote_button);
+                ((AnimationDrawable) button.getDrawable()).start();
+            }
+        });
+        enterAnimator.start();
+    }
+
+    private Animator loadAnimator(int viewResId, int animResId) {
+        Animator animator = AnimatorInflater.loadAnimator(this, animResId);
+        animator.setTarget(findViewById(viewResId));
+        return animator;
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        finish();
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
index 8b8c105..9c806f7 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsControlsView.java
@@ -72,28 +72,20 @@
         super.onFinishInflate();
 
         int buttonsFocusGainAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_gain_animation;
-        int textFocusGainAnim = R.anim.tv_pip_controls_text_in_recents_focus_gain_animation;
         mFocusGainAnimatorSet = new AnimatorSet();
         mFocusGainAnimatorSet.playTogether(
                 loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_gain_animation),
                 loadAnimator(mFullButtonView,buttonsFocusGainAnim),
-                loadAnimator(mPlayPauseButtonImageView, buttonsFocusGainAnim),
-                loadAnimator(mCloseButtonView, buttonsFocusGainAnim),
-                loadAnimator(mFullDescriptionView, textFocusGainAnim),
-                loadAnimator(mPlayPauseDescriptionTextView, textFocusGainAnim),
-                loadAnimator(mCloseDescriptionView, textFocusGainAnim));
+                loadAnimator(mPlayPauseButtonView, buttonsFocusGainAnim),
+                loadAnimator(mCloseButtonView, buttonsFocusGainAnim));
 
         int buttonsFocusLoseAnim = R.anim.tv_pip_controls_buttons_in_recents_focus_lose_animation;
-        int textFocusLoseAnim = R.anim.tv_pip_controls_text_in_recents_focus_lose_animation;
         mFocusLoseAnimatorSet = new AnimatorSet();
         mFocusLoseAnimatorSet.playTogether(
                 loadAnimator(this, R.anim.tv_pip_controls_in_recents_focus_lose_animation),
                 loadAnimator(mFullButtonView, buttonsFocusLoseAnim),
-                loadAnimator(mPlayPauseButtonImageView, buttonsFocusLoseAnim),
-                loadAnimator(mCloseButtonView, buttonsFocusLoseAnim),
-                loadAnimator(mFullDescriptionView, textFocusLoseAnim),
-                loadAnimator(mPlayPauseDescriptionTextView, textFocusLoseAnim),
-                loadAnimator(mCloseDescriptionView, textFocusLoseAnim));
+                loadAnimator(mPlayPauseButtonView, buttonsFocusLoseAnim),
+                loadAnimator(mCloseButtonView, buttonsFocusLoseAnim));
 
         Rect pipBounds = mPipManager.getRecentsFocusedPipBounds();
         int pipControlsMarginTop = getContext().getResources().getDimensionPixelSize(
@@ -142,11 +134,8 @@
         requestFocus();
         setTranslationY(0);
         setScaleXY(mFullButtonView, 1);
-        setScaleXY(mPlayPauseButtonImageView, 1);
+        setScaleXY(mPlayPauseButtonView, 1);
         setScaleXY(mCloseButtonView, 1);
-        mFullDescriptionView.setAlpha(1);
-        mPlayPauseDescriptionTextView.setAlpha(1);
-        mCloseDescriptionView.setAlpha(1);
     }
 
     private void setScaleXY(View view, float scale) {
diff --git a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
index 47cd8e5..d75561b 100644
--- a/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
+++ b/packages/SystemUI/src/com/android/systemui/tv/pip/PipRecentsOverlayManager.java
@@ -16,8 +16,6 @@
 
 package com.android.systemui.tv.pip;
 
-import android.animation.AnimatorInflater;
-import android.animation.AnimatorSet;
 import android.content.Context;
 import android.graphics.PixelFormat;
 import android.util.Log;
@@ -134,6 +132,7 @@
      * @param allowRecentsFocusable {@code true} if Recents can have focus. (i.e. Has a recent task)
      */
     public void requestFocus(boolean allowRecentsFocusable) {
+        mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
         if (!mIsRecentsShown || mIsPipFocusedInRecent) {
             return;
         }
@@ -143,7 +142,6 @@
         mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewFocusedLayoutParams);
         mPipControlsView.requestFocus();
         mPipControlsView.startFocusGainAnimation();
-        mRecentsView.setVisibility(allowRecentsFocusable ? View.VISIBLE : View.GONE);
     }
 
     /**
@@ -152,10 +150,14 @@
      * is focused.
      * This should be called only by {@link com.android.systemui.recents.tv.RecentsTvActivity}.
      */
-    private void clearFocus() {
+    public void clearFocus() {
         if (!mIsRecentsShown || !mIsPipFocusedInRecent) {
             return;
         }
+        if (!mRecentsView.hasFocus()) {
+            // Let mRecentsView's focus listener handle clearFocus().
+            mRecentsView.requestFocus();
+        }
         mIsPipFocusedInRecent = false;
         mPipManager.resizePinnedStack(STATE_PIP_RECENTS);
         mWindowManager.updateViewLayout(mOverlayView, mPipRecentsControlsViewLayoutParams);
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
index 613f890..4d7f82d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -70,12 +70,22 @@
     static final int FLAG_FEATURE_AUTOCLICK = 0x00000008;
 
     /**
-     * Flag for enabling motion event injectsion
+     * Flag for enabling motion event injection.
      *
      * @see #setUserAndEnabledFeatures(int, int)
      */
     static final int FLAG_FEATURE_INJECT_MOTION_EVENTS = 0x00000010;
 
+    /**
+     * Flag for enabling the feature to control the screen magnifier. If
+     * {@link #FLAG_FEATURE_SCREEN_MAGNIFIER} is set this flag is ignored
+     * as the screen magnifier feature performs a super set of the work
+     * performed by this feature.
+     *
+     * @see #setUserAndEnabledFeatures(int, int)
+     */
+    static final int FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER = 0x00000020;
+
     private final Runnable mProcessBatchedEventsRunnable = new Runnable() {
         @Override
         public void run() {
@@ -373,8 +383,12 @@
             addFirstEventHandler(mTouchExplorer);
         }
 
-        if ((mEnabledFeatures & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
-            mMagnificationGestureHandler = new MagnificationGestureHandler(mContext, mAms);
+        if ((mEnabledFeatures & FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER) != 0
+                || (mEnabledFeatures  & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0) {
+            final boolean detectControlGestures = (mEnabledFeatures
+                    & FLAG_FEATURE_SCREEN_MAGNIFIER) != 0;
+            mMagnificationGestureHandler = new MagnificationGestureHandler(
+                    mContext, mAms, detectControlGestures);
             addFirstEventHandler(mMagnificationGestureHandler);
         }
 
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index ca17c43..d900b37 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -1311,6 +1311,9 @@
             if (userState.mIsDisplayMagnificationEnabled) {
                 flags |= AccessibilityInputFilter.FLAG_FEATURE_SCREEN_MAGNIFIER;
             }
+            if (userHasMagnificationServicesLocked(userState)) {
+                flags |= AccessibilityInputFilter.FLAG_FEATURE_CONTROL_SCREEN_MAGNIFIER;
+            }
             // Touch exploration without accessibility makes no sense.
             if (userState.isHandlingAccessibilityEvents()
                     && userState.mIsTouchExplorationEnabled) {
diff --git a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
index 51c8ab5..818ac81 100644
--- a/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/MagnificationGestureHandler.java
@@ -80,7 +80,6 @@
     private static final boolean DEBUG_STATE_TRANSITIONS = false;
     private static final boolean DEBUG_DETECTING = false;
     private static final boolean DEBUG_PANNING = false;
-    private static final boolean DEBUG_SCALING = false;
 
     private static final int STATE_DELEGATING = 1;
     private static final int STATE_DETECTING = 2;
@@ -95,6 +94,9 @@
     private final MagnifiedContentInteractionStateHandler mMagnifiedContentInteractionStateHandler;
     private final StateViewportDraggingHandler mStateViewportDraggingHandler;
 
+
+    private final boolean mDetectControlGestures;
+
     private EventStreamTransformation mNext;
 
     private int mCurrentState;
@@ -107,12 +109,14 @@
 
     private long mDelegatingStateDownTime;
 
-    public MagnificationGestureHandler(Context context, AccessibilityManagerService ams) {
+    public MagnificationGestureHandler(Context context, AccessibilityManagerService ams,
+            boolean detectControlGestures) {
         mMagnificationController = ams.getMagnificationController();
         mDetectingStateHandler = new DetectingStateHandler(context);
         mStateViewportDraggingHandler = new StateViewportDraggingHandler();
         mMagnifiedContentInteractionStateHandler =
                 new MagnifiedContentInteractionStateHandler(context);
+        mDetectControlGestures = detectControlGestures;
 
         transitionToState(STATE_DETECTING);
     }
@@ -125,6 +129,12 @@
             }
             return;
         }
+        if (!mDetectControlGestures) {
+            if (mNext != null) {
+                dispatchTransformedEvent(event, rawEvent, policyFlags);
+            }
+            return;
+        }
         mMagnifiedContentInteractionStateHandler.onMotionEvent(event, rawEvent, policyFlags);
         switch (mCurrentState) {
             case STATE_DELEGATING: {
@@ -140,7 +150,7 @@
             }
             break;
             case STATE_MAGNIFIED_INTERACTION: {
-                // mMagnifiedContentInteractonStateHandler handles events only
+                // mMagnifiedContentInteractionStateHandler handles events only
                 // if this is the current state since it uses ScaleGestureDetecotr
                 // and a GestureDetector which need well formed event stream.
             }
@@ -208,31 +218,6 @@
             break;
         }
         if (mNext != null) {
-            // If the event is within the magnified portion of the screen we have
-            // to change its location to be where the user thinks he is poking the
-            // UI which may have been magnified and panned.
-            final float eventX = event.getX();
-            final float eventY = event.getY();
-            if (mMagnificationController.isMagnifying()
-                    && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
-                final float scale = mMagnificationController.getScale();
-                final float scaledOffsetX = mMagnificationController.getOffsetX();
-                final float scaledOffsetY = mMagnificationController.getOffsetY();
-                final int pointerCount = event.getPointerCount();
-                PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
-                PointerProperties[] properties = getTempPointerPropertiesWithMinSize(
-                        pointerCount);
-                for (int i = 0; i < pointerCount; i++) {
-                    event.getPointerCoords(i, coords[i]);
-                    coords[i].x = (coords[i].x - scaledOffsetX) / scale;
-                    coords[i].y = (coords[i].y - scaledOffsetY) / scale;
-                    event.getPointerProperties(i, properties[i]);
-                }
-                event = MotionEvent.obtain(event.getDownTime(),
-                        event.getEventTime(), event.getAction(), pointerCount, properties,
-                        coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
-                        event.getFlags());
-            }
             // We cache some events to see if the user wants to trigger magnification.
             // If no magnification is triggered we inject these events with adjusted
             // time and down time to prevent subsequent transformations being confused
@@ -240,10 +225,40 @@
             // injected we need to also update the down time of all subsequent non cached
             // events. All delegated events cached and non-cached are delivered here.
             event.setDownTime(mDelegatingStateDownTime);
-            mNext.onMotionEvent(event, rawEvent, policyFlags);
+            dispatchTransformedEvent(event, rawEvent, policyFlags);
         }
     }
 
+    private void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent,
+            int policyFlags) {
+        // If the event is within the magnified portion of the screen we have
+        // to change its location to be where the user thinks he is poking the
+        // UI which may have been magnified and panned.
+        final float eventX = event.getX();
+        final float eventY = event.getY();
+        if (mMagnificationController.isMagnifying()
+                && mMagnificationController.magnifiedRegionContains(eventX, eventY)) {
+            final float scale = mMagnificationController.getScale();
+            final float scaledOffsetX = mMagnificationController.getOffsetX();
+            final float scaledOffsetY = mMagnificationController.getOffsetY();
+            final int pointerCount = event.getPointerCount();
+            PointerCoords[] coords = getTempPointerCoordsWithMinSize(pointerCount);
+            PointerProperties[] properties = getTempPointerPropertiesWithMinSize(
+                    pointerCount);
+            for (int i = 0; i < pointerCount; i++) {
+                event.getPointerCoords(i, coords[i]);
+                coords[i].x = (coords[i].x - scaledOffsetX) / scale;
+                coords[i].y = (coords[i].y - scaledOffsetY) / scale;
+                event.getPointerProperties(i, properties[i]);
+            }
+            event = MotionEvent.obtain(event.getDownTime(),
+                    event.getEventTime(), event.getAction(), pointerCount, properties,
+                    coords, 0, 0, 1.0f, 1.0f, event.getDeviceId(), 0, event.getSource(),
+                    event.getFlags());
+        }
+        mNext.onMotionEvent(event, rawEvent, policyFlags);
+    }
+
     private PointerCoords[] getTempPointerCoordsWithMinSize(int size) {
         final int oldSize = (mTempPointerCoords != null) ? mTempPointerCoords.length : 0;
         if (oldSize < size) {
diff --git a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
index 6ca3af8..0428ecf 100644
--- a/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
+++ b/services/appwidget/java/com/android/server/appwidget/AppWidgetServiceImpl.java
@@ -613,23 +613,22 @@
                             | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
                 }
             }
+            for (int j = 0; j < widgetCount; j++) {
+                Widget widget = provider.widgets.get(j);
+                if (targetWidget != null && targetWidget != widget) continue;
+                PendingIntent intent = null;
+                if (onClickIntent != null) {
+                    intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
+                            onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
+                }
+                RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
+                if (widget.replaceWithMaskedViewsLocked(views)) {
+                    scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
+                }
+            }
         } finally {
             Binder.restoreCallingIdentity(identity);
         }
-
-        for (int j = 0; j < widgetCount; j++) {
-            Widget widget = provider.widgets.get(j);
-            if (targetWidget != null && targetWidget != widget) continue;
-            PendingIntent intent = null;
-            if (onClickIntent != null) {
-                intent = PendingIntent.getActivity(mContext, widget.appWidgetId,
-                        onClickIntent, PendingIntent.FLAG_UPDATE_CURRENT);
-            }
-            RemoteViews views = createMaskedWidgetRemoteViews(iconBitmap, showBadge, intent);
-            if (widget.replaceWithMaskedViewsLocked(views)) {
-                scheduleNotifyUpdateAppWidgetLocked(widget, widget.getEffectiveViewsLocked());
-            }
-        }
     }
 
     private void unmaskWidgetsViewsLocked(Provider provider) {
@@ -1062,8 +1061,6 @@
             widget.provider = provider;
             widget.options = (options != null) ? cloneIfLocalBinder(options) : new Bundle();
 
-            onWidgetProviderAddedOrChangedLocked(widget);
-
             // We need to provide a default value for the widget category if it is not specified
             if (!widget.options.containsKey(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY)) {
                 widget.options.putInt(AppWidgetManager.OPTION_APPWIDGET_HOST_CATEGORY,
@@ -1072,6 +1069,8 @@
 
             provider.widgets.add(widget);
 
+            onWidgetProviderAddedOrChangedLocked(widget);
+
             final int widgetCount = provider.widgets.size();
             if (widgetCount == 1) {
                 // Tell the provider that it's ready.
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 2ccc3fe..e5fe03a 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2206,6 +2206,10 @@
             }
             mLegacyTypeTracker.remove(nai, wasDefault);
             rematchAllNetworksAndRequests(null, 0);
+            if (wasDefault && getDefaultNetwork() == null) {
+                // Log that we lost the default network and there is no replacement.
+                logConnectivityServiceChangeEvent(null, nai);
+            }
             if (nai.created) {
                 // Tell netd to clean up the configuration for this network
                 // (routing rules, DNS, etc).
@@ -4427,9 +4431,8 @@
         teardownUnneededNetwork(oldNetwork);
     }
 
-    private void makeDefault(NetworkAgentInfo newNetwork) {
+    private void makeDefault(NetworkAgentInfo newNetwork, NetworkAgentInfo prevNetwork) {
         if (DBG) log("Switching to new default network: " + newNetwork);
-        ConnectivityServiceChangeEvent.logEvent(newNetwork.network.netId);
         setupDataActivityTracking(newNetwork);
         try {
             mNetd.setDefaultNetId(newNetwork.network.netId);
@@ -4440,6 +4443,8 @@
         handleApplyDefaultProxy(newNetwork.linkProperties.getHttpProxy());
         updateTcpBufferSizes(newNetwork);
         setDefaultDnsSystemProperties(newNetwork.linkProperties.getDnsServers());
+
+        logConnectivityServiceChangeEvent(newNetwork, prevNetwork);
     }
 
     // Handles a network appearing or improving its score.
@@ -4590,7 +4595,7 @@
         }
         if (isNewDefault) {
             // Notify system services that this network is up.
-            makeDefault(newNetwork);
+            makeDefault(newNetwork, oldDefaultNetwork);
             synchronized (ConnectivityService.this) {
                 // have a new default network, release the transition wakelock in
                 // a second if it's held.  The second pause is to allow apps
@@ -5060,4 +5065,22 @@
             NetworkAgentInfo nai, NetworkRequest defaultRequest) {
         return new NetworkMonitor(context, handler, nai, defaultRequest);
     }
+
+    private static void logConnectivityServiceChangeEvent(
+            NetworkAgentInfo next, NetworkAgentInfo prev) {
+        final int newNetId = (next == null) ? NETID_UNSET : next.network.netId;
+        final int[] newTransportTypes = (next == null)
+                ? new int[0]
+                : next.networkCapabilities.getTransportTypes();
+
+        final int oldNetId = (prev == null) ? NETID_UNSET : prev.network.netId;
+        final boolean hadIPv4 = (prev != null) &&
+                prev.linkProperties.hasIPv4Address() &&
+                prev.linkProperties.hasIPv4DefaultRoute();
+        final boolean hadIPv6 = (prev != null) &&
+                prev.linkProperties.hasGlobalIPv6Address() &&
+                prev.linkProperties.hasIPv6DefaultRoute();
+        ConnectivityServiceChangeEvent.logEvent(newNetId, newTransportTypes,
+                oldNetId, hadIPv4, hadIPv6);
+    }
 }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 4ac75ca..f2b4e52 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -229,7 +229,6 @@
         filter.addAction(Intent.ACTION_USER_ADDED);
         filter.addAction(Intent.ACTION_USER_STARTING);
         filter.addAction(Intent.ACTION_USER_REMOVED);
-        filter.addAction(Intent.ACTION_USER_PRESENT);
         mContext.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
 
         mStorage = new LockSettingsStorage(context, new LockSettingsStorage.Callback() {
@@ -369,8 +368,6 @@
             } else if (Intent.ACTION_USER_STARTING.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 mStorage.prefetchUser(userHandle);
-            } else if (Intent.ACTION_USER_PRESENT.equals(intent.getAction())) {
-                mStrongAuth.reportUnlock(getSendingUserId());
             } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
                 final int userHandle = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (userHandle > 0) {
@@ -1347,6 +1344,12 @@
         mStrongAuth.requireStrongAuth(strongAuthReason, userId);
     }
 
+    @Override
+    public void userPresent(int userId) {
+        checkWritePermission(userId);
+        mStrongAuth.reportUnlock(userId);
+    }
+
     private static final String[] VALID_SETTINGS = new String[] {
         LockPatternUtils.LOCKOUT_PERMANENT_KEY,
         LockPatternUtils.LOCKOUT_ATTEMPT_DEADLINE,
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index 2924cef..5ba07cf 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -454,6 +454,12 @@
                 return;
             }
 
+            if (vib.mUsageHint == AudioAttributes.USAGE_NOTIFICATION_RINGTONE
+                    && Settings.System.getInt(
+                    mContext.getContentResolver(), Settings.System.VIBRATE_WHEN_RINGING, 0) == 0) {
+                return;
+            }
+
             int mode = mAppOpsService.checkAudioOperation(AppOpsManager.OP_VIBRATE,
                     vib.mUsageHint, vib.mUid, vib.mOpPkg);
             if (mode == AppOpsManager.MODE_ALLOWED) {
diff --git a/services/core/java/com/android/server/Watchdog.java b/services/core/java/com/android/server/Watchdog.java
index 4198af9..be53cfc 100644
--- a/services/core/java/com/android/server/Watchdog.java
+++ b/services/core/java/com/android/server/Watchdog.java
@@ -65,10 +65,14 @@
     // Which native processes to dump into dropbox's stack traces
     public static final String[] NATIVE_STACKS_OF_INTEREST = new String[] {
         "/system/bin/audioserver",
+        "/system/bin/cameraserver",
+        "/system/bin/drmserver",
+        "/system/bin/mediadrmserver",
         "/system/bin/mediaserver",
         "/system/bin/sdcard",
         "/system/bin/surfaceflinger",
-        "media.log"
+        "media.codec",     // system/bin/mediacodec
+        "media.extractor", // system/bin/mediaextractor
     };
 
     static Watchdog sWatchdog;
diff --git a/services/core/java/com/android/server/accounts/CryptoHelper.java b/services/core/java/com/android/server/accounts/CryptoHelper.java
index 2b59b74..2ade673 100644
--- a/services/core/java/com/android/server/accounts/CryptoHelper.java
+++ b/services/core/java/com/android/server/accounts/CryptoHelper.java
@@ -10,15 +10,12 @@
 
 import java.security.GeneralSecurityException;
 import java.security.NoSuchAlgorithmException;
-import java.security.SecureRandom;
-import java.util.Arrays;
 
 import javax.crypto.Cipher;
 import javax.crypto.KeyGenerator;
 import javax.crypto.Mac;
 import javax.crypto.SecretKey;
 import javax.crypto.spec.IvParameterSpec;
-import javax.crypto.spec.SecretKeySpec;
 
 /**
  * A crypto helper for encrypting and decrypting bundle with in-memory symmetric
@@ -30,15 +27,15 @@
     private static final String KEY_CIPHER = "cipher";
     private static final String KEY_MAC = "mac";
     private static final String KEY_ALGORITHM = "AES";
+    private static final String KEY_IV = "iv";
     private static final String CIPHER_ALGORITHM = "AES/CBC/PKCS5Padding";
     private static final String MAC_ALGORITHM = "HMACSHA256";
     private static final int IV_LENGTH = 16;
 
     private static CryptoHelper sInstance;
     // Keys used for encrypting and decrypting data returned in a Bundle.
-    private final SecretKeySpec mCipherKeySpec;
-    private final SecretKeySpec mMacKeySpec;
-    private final IvParameterSpec mIv;
+    private final SecretKey mEncryptionKey;
+    private final SecretKey mMacKey;
 
     /* default */ synchronized static CryptoHelper getInstance() throws NoSuchAlgorithmException {
         if (sInstance == null) {
@@ -49,18 +46,10 @@
 
     private CryptoHelper() throws NoSuchAlgorithmException {
         KeyGenerator kgen = KeyGenerator.getInstance(KEY_ALGORITHM);
-        SecretKey skey = kgen.generateKey();
-        mCipherKeySpec = new SecretKeySpec(skey.getEncoded(), KEY_ALGORITHM);
-
+        mEncryptionKey = kgen.generateKey();
+        // Use a different key for mac-ing than encryption/decryption.
         kgen = KeyGenerator.getInstance(MAC_ALGORITHM);
-        skey = kgen.generateKey();
-        mMacKeySpec = new SecretKeySpec(skey.getEncoded(), MAC_ALGORITHM);
-
-        // Create random iv
-        byte[] iv = new byte[IV_LENGTH];
-        SecureRandom secureRandom = new SecureRandom();
-        secureRandom.nextBytes(iv);
-        mIv = new IvParameterSpec(iv);
+        mMacKey = kgen.generateKey();
     }
 
     @NonNull
@@ -68,16 +57,19 @@
         Preconditions.checkNotNull(bundle, "Cannot encrypt null bundle.");
         Parcel parcel = Parcel.obtain();
         bundle.writeToParcel(parcel, 0);
-        byte[] bytes = parcel.marshall();
+        byte[] clearBytes = parcel.marshall();
         parcel.recycle();
 
+        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+        cipher.init(Cipher.ENCRYPT_MODE, mEncryptionKey);
+        byte[] encryptedBytes = cipher.doFinal(clearBytes);
+        byte[] iv = cipher.getIV();
+        byte[] mac = createMac(encryptedBytes, iv);
+
         Bundle encryptedBundle = new Bundle();
-
-        byte[] cipher = encrypt(bytes);
-        byte[] mac = createMac(cipher);
-
-        encryptedBundle.putByteArray(KEY_CIPHER, cipher);
+        encryptedBundle.putByteArray(KEY_CIPHER, encryptedBytes);
         encryptedBundle.putByteArray(KEY_MAC, mac);
+        encryptedBundle.putByteArray(KEY_IV, iv);
 
         return encryptedBundle;
     }
@@ -85,19 +77,18 @@
     @Nullable
     /* default */ Bundle decryptBundle(@NonNull Bundle bundle) throws GeneralSecurityException {
         Preconditions.checkNotNull(bundle, "Cannot decrypt null bundle.");
-        byte[] cipherArray = bundle.getByteArray(KEY_CIPHER);
-        byte[] macArray = bundle.getByteArray(KEY_MAC);
-
-        if (!verifyMac(cipherArray, macArray)) {
-            if (Log.isLoggable(TAG, Log.VERBOSE)) {
-                Log.v(TAG, "Escrow mac mismatched!");
-            }
+        byte[] iv = bundle.getByteArray(KEY_IV);
+        byte[] encryptedBytes = bundle.getByteArray(KEY_CIPHER);
+        byte[] mac = bundle.getByteArray(KEY_MAC);
+        if (!verifyMac(encryptedBytes, iv, mac)) {
+            Log.w(TAG, "Escrow mac mismatched!");
             return null;
         }
 
+        IvParameterSpec ivSpec = new IvParameterSpec(iv);
         Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
-        cipher.init(Cipher.DECRYPT_MODE, mCipherKeySpec, mIv);
-        byte[] decryptedBytes = cipher.doFinal(cipherArray);
+        cipher.init(Cipher.DECRYPT_MODE, mEncryptionKey, ivSpec);
+        byte[] decryptedBytes = cipher.doFinal(encryptedBytes);
 
         Parcel decryptedParcel = Parcel.obtain();
         decryptedParcel.unmarshall(decryptedBytes, 0, decryptedBytes.length);
@@ -108,9 +99,8 @@
         return decryptedBundle;
     }
 
-    private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] macArray)
+    private boolean verifyMac(@Nullable byte[] cipherArray, @Nullable byte[] iv, @Nullable byte[] macArray)
             throws GeneralSecurityException {
-
         if (cipherArray == null || cipherArray.length == 0 || macArray == null
                 || macArray.length == 0) {
             if (Log.isLoggable(TAG, Log.VERBOSE)) {
@@ -118,23 +108,29 @@
             }
             return false;
         }
-        Mac mac = Mac.getInstance(MAC_ALGORITHM);
-        mac.init(mMacKeySpec);
-        mac.update(cipherArray);
-        return Arrays.equals(macArray, mac.doFinal());
+        return constantTimeArrayEquals(macArray, createMac(cipherArray, iv));
     }
 
     @NonNull
-    private byte[] encrypt(@NonNull byte[] data) throws GeneralSecurityException {
-        Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
-        cipher.init(Cipher.ENCRYPT_MODE, mCipherKeySpec, mIv);
-        return cipher.doFinal(data);
+    private byte[] createMac(@NonNull byte[] cipher, @NonNull byte[] iv) throws GeneralSecurityException {
+        Mac mac = Mac.getInstance(MAC_ALGORITHM);
+        mac.init(mMacKey);
+        mac.update(cipher);
+        mac.update(iv);
+        return mac.doFinal();
     }
 
-    @NonNull
-    private byte[] createMac(@NonNull byte[] cipher) throws GeneralSecurityException {
-        Mac mac = Mac.getInstance(MAC_ALGORITHM);
-        mac.init(mMacKeySpec);
-        return mac.doFinal(cipher);
+    private static boolean constantTimeArrayEquals(byte[] a, byte[] b) {
+        if (a == null || b == null) {
+            return a == b;
+        }
+        if (a.length != b.length) {
+            return false;
+        }
+        boolean isEqual = true;
+        for (int i = 0; i < b.length; i++) {
+            isEqual &= (a[i] == b[i]);
+        }
+        return isEqual;
     }
 }
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index c01b4f5..9703d13 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -628,13 +628,16 @@
         public Bundle result = null;
         public AssistStructure structure = null;
         public AssistContent content = null;
+        public Bundle receiverExtras;
+
         public PendingAssistExtras(ActivityRecord _activity, Bundle _extras, Intent _intent,
-                String _hint, IResultReceiver _receiver, int _userHandle) {
+                String _hint, IResultReceiver _receiver, Bundle _receiverExtras, int _userHandle) {
             activity = _activity;
             extras = _extras;
             intent = _intent;
             hint = _hint;
             receiver = _receiver;
+            receiverExtras = _receiverExtras;
             userHandle = _userHandle;
         }
         @Override
@@ -9425,7 +9428,8 @@
             if (prev != null && prev.isRecentsActivity()) {
                 task.setTaskToReturnTo(ActivityRecord.RECENTS_ACTIVITY_TYPE);
             }
-            mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront");
+            mStackSupervisor.findTaskToMoveToFrontLocked(task, flags, options, "moveTaskToFront",
+                    false /* forceNonResizable */);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -11805,7 +11809,7 @@
     @Override
     public Bundle getAssistContextExtras(int requestType) {
         PendingAssistExtras pae = enqueueAssistContext(requestType, null, null, null,
-                null, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
+                null, null, true, UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_TIMEOUT);
         if (pae == null) {
             return null;
         }
@@ -11869,14 +11873,17 @@
 
     @Override
     public boolean requestAssistContextExtras(int requestType, IResultReceiver receiver,
-            IBinder activityToken) {
-        return enqueueAssistContext(requestType, null, null, receiver, activityToken,
-                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT) != null;
+            Bundle receiverExtras,
+            IBinder activityToken, boolean focused) {
+        return enqueueAssistContext(requestType, null, null, receiver, receiverExtras,
+                activityToken, focused,
+                UserHandle.getCallingUserId(), null, PENDING_ASSIST_EXTRAS_LONG_TIMEOUT)
+                != null;
     }
 
     private PendingAssistExtras enqueueAssistContext(int requestType, Intent intent, String hint,
-            IResultReceiver receiver, IBinder activityToken, int userHandle, Bundle args,
-            long timeout) {
+            IResultReceiver receiver, Bundle receiverExtras, IBinder activityToken, boolean focused,
+            int userHandle, Bundle args, long timeout) {
         enforceCallingPermission(android.Manifest.permission.GET_TOP_ACTIVITY_INFO,
                 "enqueueAssistContext()");
         synchronized (this) {
@@ -11889,14 +11896,24 @@
                 Slog.w(TAG, "getAssistContextExtras failed: no process for " + activity);
                 return null;
             }
-            if (activityToken != null) {
-                ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
-                if (activity != caller) {
-                    Slog.w(TAG, "enqueueAssistContext failed: caller " + caller
-                            + " is not current top " + activity);
+            if (focused) {
+                if (activityToken != null) {
+                    ActivityRecord caller = ActivityRecord.forTokenLocked(activityToken);
+                    if (activity != caller) {
+                        Slog.w(TAG, "enqueueAssistContext failed: caller " + caller
+                                + " is not current top " + activity);
+                        return null;
+                    }
+                }
+            } else {
+                activity = ActivityRecord.forTokenLocked(activityToken);
+                if (activity == null) {
+                    Slog.w(TAG, "enqueueAssistContext failed: activity for token=" + activityToken
+                            + " couldn't be found");
                     return null;
                 }
             }
+
             PendingAssistExtras pae;
             Bundle extras = new Bundle();
             if (args != null) {
@@ -11904,7 +11921,8 @@
             }
             extras.putString(Intent.EXTRA_ASSIST_PACKAGE, activity.packageName);
             extras.putInt(Intent.EXTRA_ASSIST_UID, activity.app.uid);
-            pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, userHandle);
+            pae = new PendingAssistExtras(activity, extras, intent, hint, receiver, receiverExtras,
+                    userHandle);
             try {
                 activity.app.thread.requestAssistContextExtras(activity.appToken, pae,
                         requestType);
@@ -11974,9 +11992,11 @@
             if ((sendReceiver=pae.receiver) != null) {
                 // Caller wants result sent back to them.
                 sendBundle = new Bundle();
-                sendBundle.putBundle("data", pae.extras);
-                sendBundle.putParcelable("structure", pae.structure);
-                sendBundle.putParcelable("content", pae.content);
+                sendBundle.putBundle(VoiceInteractionSession.KEY_DATA, pae.extras);
+                sendBundle.putParcelable(VoiceInteractionSession.KEY_STRUCTURE, pae.structure);
+                sendBundle.putParcelable(VoiceInteractionSession.KEY_CONTENT, pae.content);
+                sendBundle.putBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS,
+                        pae.receiverExtras);
             }
         }
         if (sendReceiver != null) {
@@ -12006,8 +12026,8 @@
 
     public boolean launchAssistIntent(Intent intent, int requestType, String hint, int userHandle,
             Bundle args) {
-        return enqueueAssistContext(requestType, intent, hint, null, null, userHandle, args,
-                PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
+        return enqueueAssistContext(requestType, intent, hint, null, null, null, true,
+                userHandle, args, PENDING_ASSIST_EXTRAS_TIMEOUT) != null;
     }
 
     public void registerProcessObserver(IProcessObserver observer) {
@@ -17621,7 +17641,7 @@
             int res = broadcastIntentLocked(callerApp,
                     callerApp != null ? callerApp.info.packageName : null,
                     intent, resolvedType, resultTo, resultCode, resultData, resultExtras,
-                    requiredPermissions, appOp, null, serialized, sticky,
+                    requiredPermissions, appOp, bOptions, serialized, sticky,
                     callingPid, callingUid, userId);
             Binder.restoreCallingIdentity(origId);
             return res;
@@ -20961,6 +20981,13 @@
                 mStackSupervisor.notifyAppTransitionDone();
             }
         }
+
+        @Override
+        public List<IBinder> getTopVisibleActivities() {
+            synchronized (ActivityManagerService.this) {
+                return mStackSupervisor.getTopVisibleActivities();
+            }
+        }
     }
 
     private final class SleepTokenImpl extends SleepToken {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 53c6024..ab3a0b3 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -98,6 +98,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.Set;
@@ -1759,8 +1760,8 @@
         }
     }
 
-    void findTaskToMoveToFrontLocked(
-            TaskRecord task, int flags, ActivityOptions options, String reason) {
+    void findTaskToMoveToFrontLocked(TaskRecord task, int flags, ActivityOptions options,
+            String reason, boolean forceNonResizeable) {
         if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
             mUserLeaving = true;
         }
@@ -1811,7 +1812,8 @@
         if (DEBUG_STACK) Slog.d(TAG_STACK,
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
 
-        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId);
+        handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+                forceNonResizeable);
     }
 
     boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
@@ -3360,19 +3362,25 @@
         }
     }
 
+    void handleNonResizableTaskIfNeeded(TaskRecord task, int preferredStackId, int actualStackId) {
+        handleNonResizableTaskIfNeeded(task, preferredStackId, actualStackId,
+                false /* forceNonResizable */);
+    }
+
     void handleNonResizableTaskIfNeeded(
-            TaskRecord task, int preferredStackId, int actualStackId) {
+            TaskRecord task, int preferredStackId, int actualStackId, boolean forceNonResizable) {
         if ((!isStackDockedInEffect(actualStackId) && preferredStackId != DOCKED_STACK_ID)
                 || task.isHomeTask()) {
             return;
         }
 
-        if (!task.canGoInDockedStack()) {
+        if (!task.canGoInDockedStack() || forceNonResizable) {
             // Display a warning toast that we tried to put a non-dockable task in the docked stack.
             mService.mHandler.sendEmptyMessage(NOTIFY_ACTIVITY_DISMISSING_DOCKED_STACK_MSG);
 
-            // Dismiss docked stack.
-            mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, false);
+            // Dismiss docked stack. If task appeared to be in docked stack but is not resizable -
+            // we need to move it to top of fullscreen stack, otherwise it will be covered.
+            mService.moveTasksToFullscreenStack(DOCKED_STACK_ID, actualStackId == DOCKED_STACK_ID);
         } else if (task.mResizeMode == RESIZE_MODE_FORCE_RESIZEABLE) {
             String packageName = task.getTopActivity() != null
                     ? task.getTopActivity().appInfo.packageName : null;
@@ -3443,8 +3451,12 @@
         }
 
         if (andResume) {
-            findTaskToMoveToFrontLocked(task, 0, null, reason);
+            findTaskToMoveToFrontLocked(task, 0, null, reason,
+                    lockTaskModeState != LOCK_TASK_MODE_NONE);
             resumeFocusedStackTopActivityLocked();
+        } else if (lockTaskModeState != LOCK_TASK_MODE_NONE) {
+            handleNonResizableTaskIfNeeded(task, INVALID_STACK_ID, task.stack.mStackId,
+                    true /* forceNonResizable */);
         }
     }
 
@@ -4271,4 +4283,31 @@
             }
             return result;
     }
+
+    /**
+     * @return a list of activities which are the top ones in each visible stack. The first
+     * entry will be the focused activity.
+     */
+    public List<IBinder> getTopVisibleActivities() {
+        final ActivityDisplay display = mActivityDisplays.get(Display.DEFAULT_DISPLAY);
+        if (display == null) {
+            return Collections.EMPTY_LIST;
+        }
+        ArrayList<IBinder> topActivityTokens = new ArrayList<>();
+        final ArrayList<ActivityStack> stacks = display.mStacks;
+        for (int i = stacks.size() - 1; i >= 0; i--) {
+            ActivityStack stack = stacks.get(i);
+            if (stack.getStackVisibilityLocked(null) == ActivityStack.STACK_VISIBLE) {
+                ActivityRecord top = stack.topActivity();
+                if (top != null) {
+                    if (stack == mFocusedStack) {
+                        topActivityTokens.add(0, top.appToken);
+                    } else {
+                        topActivityTokens.add(top.appToken);
+                    }
+                }
+            }
+        }
+        return topActivityTokens;
+    }
 }
diff --git a/services/core/java/com/android/server/job/JobPackageTracker.java b/services/core/java/com/android/server/job/JobPackageTracker.java
new file mode 100644
index 0000000..e5a2095
--- /dev/null
+++ b/services/core/java/com/android/server/job/JobPackageTracker.java
@@ -0,0 +1,361 @@
+/*
+ * 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.job;
+
+import android.app.job.JobInfo;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.text.format.DateFormat;
+import android.util.ArrayMap;
+import android.util.SparseArray;
+import android.util.TimeUtils;
+import com.android.server.job.controllers.JobStatus;
+
+import java.io.PrintWriter;
+
+public final class JobPackageTracker {
+    // We batch every 30 minutes.
+    static final long BATCHING_TIME = 30*60*1000;
+    // Number of historical data sets we keep.
+    static final int NUM_HISTORY = 5;
+
+    DataSet mCurDataSet = new DataSet();
+    DataSet[] mLastDataSets = new DataSet[NUM_HISTORY];
+
+    final static class PackageEntry {
+        long pastActiveTime;
+        long activeStartTime;
+        int activeCount;
+        boolean hadActive;
+        long pastActiveTopTime;
+        long activeTopStartTime;
+        int activeTopCount;
+        boolean hadActiveTop;
+        long pastPendingTime;
+        long pendingStartTime;
+        int pendingCount;
+        boolean hadPending;
+
+        public long getActiveTime(long now) {
+            long time = pastActiveTime;
+            if (activeCount > 0) {
+                time += now - activeStartTime;
+            }
+            return time;
+        }
+
+        public long getActiveTopTime(long now) {
+            long time = pastActiveTopTime;
+            if (activeTopCount > 0) {
+                time += now - activeTopStartTime;
+            }
+            return time;
+        }
+
+        public long getPendingTime(long now) {
+            long time = pastPendingTime;
+            if (pendingCount > 0) {
+                time += now - pendingStartTime;
+            }
+            return time;
+        }
+    }
+
+    final static class DataSet {
+        final SparseArray<ArrayMap<String, PackageEntry>> mEntries = new SparseArray<>();
+        final long mStartUptimeTime;
+        final long mStartElapsedTime;
+        final long mStartClockTime;
+        long mSummedTime;
+
+        public DataSet(DataSet otherTimes) {
+            mStartUptimeTime = otherTimes.mStartUptimeTime;
+            mStartElapsedTime = otherTimes.mStartElapsedTime;
+            mStartClockTime = otherTimes.mStartClockTime;
+        }
+
+        public DataSet() {
+            mStartUptimeTime = SystemClock.uptimeMillis();
+            mStartElapsedTime = SystemClock.elapsedRealtime();
+            mStartClockTime = System.currentTimeMillis();
+        }
+
+        private PackageEntry getOrCreateEntry(int uid, String pkg) {
+            ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+            if (uidMap == null) {
+                uidMap = new ArrayMap<>();
+                mEntries.put(uid, uidMap);
+            }
+            PackageEntry entry = uidMap.get(pkg);
+            if (entry == null) {
+                entry = new PackageEntry();
+                uidMap.put(pkg, entry);
+            }
+            return entry;
+        }
+
+        public PackageEntry getEntry(int uid, String pkg) {
+            ArrayMap<String, PackageEntry> uidMap = mEntries.get(uid);
+            if (uidMap == null) {
+                return null;
+            }
+            return uidMap.get(pkg);
+        }
+
+        long getTotalTime(long now) {
+            if (mSummedTime > 0) {
+                return mSummedTime;
+            }
+            return now - mStartUptimeTime;
+        }
+
+        void incPending(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.pendingCount == 0) {
+                pe.pendingStartTime = now;
+            }
+            pe.pendingCount++;
+        }
+
+        void decPending(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.pendingCount == 1) {
+                pe.pastPendingTime += now - pe.pendingStartTime;
+            }
+            pe.pendingCount--;
+        }
+
+        void incActive(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeCount == 0) {
+                pe.activeStartTime = now;
+            }
+            pe.activeCount++;
+        }
+
+        void decActive(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeCount == 1) {
+                pe.pastActiveTime += now - pe.activeStartTime;
+            }
+            pe.activeCount--;
+        }
+
+        void incActiveTop(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeTopCount == 0) {
+                pe.activeTopStartTime = now;
+            }
+            pe.activeTopCount++;
+        }
+
+        void decActiveTop(int uid, String pkg, long now) {
+            PackageEntry pe = getOrCreateEntry(uid, pkg);
+            if (pe.activeTopCount == 1) {
+                pe.pastActiveTopTime += now - pe.activeTopStartTime;
+            }
+            pe.activeTopCount--;
+        }
+
+        void finish(DataSet next, long now) {
+            for (int i = mEntries.size() - 1; i >= 0; i--) {
+                ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+                for (int j = uidMap.size() - 1; j >= 0; j--) {
+                    PackageEntry pe = uidMap.valueAt(j);
+                    if (pe.activeCount > 0 || pe.activeTopCount > 0 || pe.pendingCount > 0) {
+                        // Propagate existing activity in to next data set.
+                        PackageEntry nextPe = next.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+                        nextPe.activeStartTime = now;
+                        nextPe.activeCount = pe.activeCount;
+                        nextPe.activeTopStartTime = now;
+                        nextPe.activeTopCount = pe.activeTopCount;
+                        nextPe.pendingStartTime = now;
+                        nextPe.pendingCount = pe.pendingCount;
+                        // Finish it off.
+                        if (pe.activeCount > 0) {
+                            pe.pastActiveTime += now - pe.activeStartTime;
+                            pe.activeCount = 0;
+                        }
+                        if (pe.activeTopCount > 0) {
+                            pe.pastActiveTopTime += now - pe.activeTopStartTime;
+                            pe.activeTopCount = 0;
+                        }
+                        if (pe.pendingCount > 0) {
+                            pe.pastPendingTime += now - pe.pendingStartTime;
+                            pe.pendingCount = 0;
+                        }
+                    }
+                }
+            }
+        }
+
+        void addTo(DataSet out, long now) {
+            out.mSummedTime += getTotalTime(now);
+            for (int i = mEntries.size() - 1; i >= 0; i--) {
+                ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+                for (int j = uidMap.size() - 1; j >= 0; j--) {
+                    PackageEntry pe = uidMap.valueAt(j);
+                    PackageEntry outPe = out.getOrCreateEntry(mEntries.keyAt(i), uidMap.keyAt(j));
+                    outPe.pastActiveTime += pe.pastActiveTime;
+                    outPe.pastActiveTopTime += pe.pastActiveTopTime;
+                    outPe.pastPendingTime += pe.pastPendingTime;
+                    if (pe.activeCount > 0) {
+                        outPe.pastActiveTime += now - pe.activeStartTime;
+                        outPe.hadActive = true;
+                    }
+                    if (pe.activeTopCount > 0) {
+                        outPe.pastActiveTopTime += now - pe.activeTopStartTime;
+                        outPe.hadActiveTop = true;
+                    }
+                    if (pe.pendingCount > 0) {
+                        outPe.pastPendingTime += now - pe.pendingStartTime;
+                        outPe.hadPending = true;
+                    }
+                }
+            }
+        }
+
+        void printDuration(PrintWriter pw, long period, long duration, String suffix) {
+            float fraction = duration / (float) period;
+            int percent = (int) ((fraction * 100) + .5f);
+            if (percent > 0) {
+                pw.print(" ");
+                pw.print(percent);
+                pw.print("% ");
+                pw.print(suffix);
+            }
+        }
+
+        void dump(PrintWriter pw, String header, String prefix, long now, long nowEllapsed) {
+            final long period = getTotalTime(now);
+            pw.print(prefix); pw.print(header); pw.print(" at ");
+            pw.print(DateFormat.format("yyyy-MM-dd-HH-mm-ss", mStartClockTime).toString());
+            pw.print(" (");
+            TimeUtils.formatDuration(mStartElapsedTime, nowEllapsed, pw);
+            pw.print(") over ");
+            TimeUtils.formatDuration(period, pw);
+            pw.println(":");
+            final int NE = mEntries.size();
+            for (int i = 0; i < NE; i++) {
+                ArrayMap<String, PackageEntry> uidMap = mEntries.valueAt(i);
+                final int NP = uidMap.size();
+                for (int j = 0; j < NP; j++) {
+                    PackageEntry pe = uidMap.valueAt(j);
+                    pw.print(prefix); pw.print("  ");
+                    UserHandle.formatUid(pw, mEntries.keyAt(i));
+                    pw.print(" / "); pw.print(uidMap.keyAt(j));
+                    pw.print(":");
+                    printDuration(pw, period, pe.getPendingTime(now), "pending");
+                    printDuration(pw, period, pe.getActiveTime(now), "active");
+                    printDuration(pw, period, pe.getActiveTopTime(now), "active-top");
+                    if (pe.pendingCount > 0 || pe.hadPending) {
+                        pw.print(" (pending)");
+                    }
+                    if (pe.activeCount > 0 || pe.hadActive) {
+                        pw.print(" (active)");
+                    }
+                    if (pe.activeTopCount > 0 || pe.hadActiveTop) {
+                        pw.print(" (active-top)");
+                    }
+                    pw.println();
+                }
+            }
+        }
+    }
+
+    void rebatchIfNeeded(long now) {
+        long totalTime = mCurDataSet.getTotalTime(now);
+        if (totalTime > BATCHING_TIME) {
+            DataSet last = mCurDataSet;
+            last.mSummedTime = totalTime;
+            mCurDataSet = new DataSet();
+            last.finish(mCurDataSet, now);
+            System.arraycopy(mLastDataSets, 0, mLastDataSets, 1, mLastDataSets.length-1);
+            mLastDataSets[0] = last;
+        }
+    }
+
+    public void notePending(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        rebatchIfNeeded(now);
+        mCurDataSet.incPending(job.getSourceUid(), job.getSourcePackageName(), now);
+    }
+
+    public void noteNonpending(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        mCurDataSet.decPending(job.getSourceUid(), job.getSourcePackageName(), now);
+        rebatchIfNeeded(now);
+    }
+
+    public void noteActive(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        rebatchIfNeeded(now);
+        if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+            mCurDataSet.incActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+        } else {
+            mCurDataSet.incActive(job.getSourceUid(), job.getSourcePackageName(), now);
+        }
+    }
+
+    public void noteInactive(JobStatus job) {
+        final long now = SystemClock.uptimeMillis();
+        if (job.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
+            mCurDataSet.decActiveTop(job.getSourceUid(), job.getSourcePackageName(), now);
+        } else {
+            mCurDataSet.decActive(job.getSourceUid(), job.getSourcePackageName(), now);
+        }
+        rebatchIfNeeded(now);
+    }
+
+    public float getLoadFactor(JobStatus job) {
+        final int uid = job.getSourceUid();
+        final String pkg = job.getSourcePackageName();
+        PackageEntry cur = mCurDataSet.getEntry(uid, pkg);
+        PackageEntry last = mLastDataSets[0] != null ? mLastDataSets[0].getEntry(uid, pkg) : null;
+        if (cur == null && last == null) {
+            return 0;
+        }
+        final long now = SystemClock.uptimeMillis();
+        long time = cur.getActiveTime(now) + cur.getPendingTime(now);
+        long period = mCurDataSet.getTotalTime(now);
+        if (last != null) {
+            time += last.getActiveTime(now) + last.getPendingTime(now);
+            period += mLastDataSets[0].getTotalTime(now);
+        }
+        return time / (float)period;
+    }
+
+    public void dump(PrintWriter pw, String prefix) {
+        final long now = SystemClock.uptimeMillis();
+        final long nowEllapsed = SystemClock.elapsedRealtime();
+        final DataSet total;
+        if (mLastDataSets[0] != null) {
+            total = new DataSet(mLastDataSets[0]);
+            mLastDataSets[0].addTo(total, now);
+        } else {
+            total = new DataSet(mCurDataSet);
+        }
+        mCurDataSet.addTo(total, now);
+        for (int i = 1; i < mLastDataSets.length; i++) {
+            if (mLastDataSets[i] != null) {
+                mLastDataSets[i].dump(pw, "Historical stats", prefix, now, nowEllapsed);
+                pw.println();
+            }
+        }
+        total.dump(pw, "Current stats", prefix, now, nowEllapsed);
+    }
+}
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index b235002..7df8ffd 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -93,16 +93,24 @@
     public static final boolean DEBUG = false;
 
     /** The maximum number of concurrent jobs we run at one time. */
-    private static final int MAX_JOB_CONTEXTS_COUNT = 8;
+    private static final int MAX_JOB_CONTEXTS_COUNT = 12;
+    /** The number of MAX_JOB_CONTEXTS_COUNT we reserve for the foreground app. */
+    private static final int FG_JOB_CONTEXTS_COUNT = 4;
     /** Enforce a per-app limit on scheduled jobs? */
     private static final boolean ENFORCE_MAX_JOBS = true;
     /** The maximum number of jobs that we allow an unprivileged app to schedule */
     private static final int MAX_JOBS_PER_APP = 100;
+    /** This is the job execution factor that is considered to be heavy use of the system. */
+    private static final float HEAVY_USE_FACTOR = .9f;
+    /** This is the job execution factor that is considered to be moderate use of the system. */
+    private static final float MODERATE_USE_FACTOR = .5f;
 
     /** Global local for all job scheduler state. */
     final Object mLock = new Object();
     /** Master list of jobs. */
     final JobStore mJobs;
+    /** Tracking amount of time each package runs for. */
+    final JobPackageTracker mJobPackageTracker = new JobPackageTracker();
 
     static final int MSG_JOB_EXPIRED = 0;
     static final int MSG_CHECK_JOB = 1;
@@ -173,7 +181,7 @@
      * Current limit on the number of concurrent JobServiceContext entries we want to
      * keep actively running a job.
      */
-    int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+    int mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
 
     /**
      * Which uids are currently in the foreground.
@@ -249,6 +257,10 @@
         return mLock;
     }
 
+    public JobStore getJobStore() {
+        return mJobs;
+    }
+
     @Override
     public void onStartUser(int userHandle) {
         mStartedUsers = ArrayUtils.appendInt(mStartedUsers, userHandle);
@@ -386,7 +398,9 @@
         stopTrackingJob(cancelled, incomingJob, true /* writeBack */);
         synchronized (mLock) {
             // Remove from pending queue.
-            mPendingJobs.remove(cancelled);
+            if (mPendingJobs.remove(cancelled)) {
+                mJobPackageTracker.noteNonpending(cancelled);
+            }
             // Cancel if running.
             stopJobOnServiceContextLocked(cancelled, JobParameters.REASON_CANCELED);
             reportActive();
@@ -518,7 +532,7 @@
                 // Create the "runners".
                 for (int i = 0; i < MAX_JOB_CONTEXTS_COUNT; i++) {
                     mActiveServices.add(
-                            new JobServiceContext(this, mBatteryStats,
+                            new JobServiceContext(this, mBatteryStats, mJobPackageTracker,
                                     getContext().getMainLooper()));
                 }
                 // Attach jobs to their controllers.
@@ -604,6 +618,20 @@
         return false;
     }
 
+    void noteJobsPending(List<JobStatus> jobs) {
+        for (int i = jobs.size() - 1; i >= 0; i--) {
+            JobStatus job = jobs.get(i);
+            mJobPackageTracker.notePending(job);
+        }
+    }
+
+    void noteJobsNonpending(List<JobStatus> jobs) {
+        for (int i = jobs.size() - 1; i >= 0; i--) {
+            JobStatus job = jobs.get(i);
+            mJobPackageTracker.noteNonpending(job);
+        }
+    }
+
     /**
      * Reschedules the given job based on the job's backoff policy. It doesn't make sense to
      * specify an override deadline on a failed job (the failed job will run even though it's not
@@ -759,6 +787,7 @@
                         // state is such that all ready jobs should be run immediately.
                         if (runNow != null && !mPendingJobs.contains(runNow)
                                 && mJobs.containsJob(runNow)) {
+                            mJobPackageTracker.notePending(runNow);
                             mPendingJobs.add(runNow);
                         }
                         queueReadyJobsForExecutionLockedH();
@@ -797,6 +826,7 @@
             if (DEBUG) {
                 Slog.d(TAG, "queuing all ready jobs for execution:");
             }
+            noteJobsNonpending(mPendingJobs);
             mPendingJobs.clear();
             mJobs.forEachJob(mReadyQueueFunctor);
             mReadyQueueFunctor.postProcess();
@@ -832,6 +862,7 @@
 
             public void postProcess() {
                 if (newReadyJobs != null) {
+                    noteJobsPending(newReadyJobs);
                     mPendingJobs.addAll(newReadyJobs);
                 }
                 newReadyJobs = null;
@@ -910,6 +941,7 @@
                     if (DEBUG) {
                         Slog.d(TAG, "maybeQueueReadyJobsForExecutionLockedH: Running jobs.");
                     }
+                    noteJobsPending(runnableJobs);
                     mPendingJobs.addAll(runnableJobs);
                 } else {
                     if (DEBUG) {
@@ -935,6 +967,7 @@
         private void maybeQueueReadyJobsForExecutionLockedH() {
             if (DEBUG) Slog.d(TAG, "Maybe queuing ready jobs...");
 
+            noteJobsNonpending(mPendingJobs);
             mPendingJobs.clear();
             mJobs.forEachJob(mMaybeQueueFunctor);
             mMaybeQueueFunctor.postProcess();
@@ -998,16 +1031,28 @@
         }
     }
 
+    private int adjustJobPriority(int curPriority, JobStatus job) {
+        if (curPriority < JobInfo.PRIORITY_TOP_APP) {
+            float factor = mJobPackageTracker.getLoadFactor(job);
+            if (factor >= HEAVY_USE_FACTOR) {
+                curPriority += JobInfo.PRIORITY_ADJ_ALWAYS_RUNNING;
+            } else if (factor >= MODERATE_USE_FACTOR) {
+                curPriority += JobInfo.PRIORITY_ADJ_OFTEN_RUNNING;
+            }
+        }
+        return curPriority;
+    }
+
     private int evaluateJobPriorityLocked(JobStatus job) {
         int priority = job.getPriority();
         if (priority >= JobInfo.PRIORITY_FOREGROUND_APP) {
-            return priority;
+            return adjustJobPriority(priority, job);
         }
         int override = mUidPriorityOverride.get(job.getSourceUid(), 0);
         if (override != 0) {
-            return override;
+            return adjustJobPriority(override, job);
         }
-        return priority;
+        return adjustJobPriority(priority, job);
     }
 
     /**
@@ -1029,16 +1074,16 @@
         }
         switch (memLevel) {
             case ProcessStats.ADJ_MEM_FACTOR_MODERATE:
-                mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - 2) * 2) / 3;
+                mMaxActiveJobs = ((MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) * 2) / 3;
                 break;
             case ProcessStats.ADJ_MEM_FACTOR_LOW:
-                mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - 2) / 3;
+                mMaxActiveJobs = (MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT) / 3;
                 break;
             case ProcessStats.ADJ_MEM_FACTOR_CRITICAL:
                 mMaxActiveJobs = 1;
                 break;
             default:
-                mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - 2;
+                mMaxActiveJobs = MAX_JOB_CONTEXTS_COUNT - FG_JOB_CONTEXTS_COUNT;
                 break;
         }
 
@@ -1134,7 +1179,9 @@
                     if (!mActiveServices.get(i).executeRunnableJob(pendingJob)) {
                         Slog.d(TAG, "Error executing " + pendingJob);
                     }
-                    mPendingJobs.remove(pendingJob);
+                    if (mPendingJobs.remove(pendingJob)) {
+                        mJobPackageTracker.noteNonpending(pendingJob);
+                    }
                 }
             }
             if (!preservePreferredUid) {
@@ -1444,6 +1491,8 @@
                 pw.print(": "); pw.println(mUidPriorityOverride.valueAt(i));
             }
             pw.println();
+            mJobPackageTracker.dump(pw, "");
+            pw.println();
             pw.println("Pending queue:");
             for (int i=0; i<mPendingJobs.size(); i++) {
                 JobStatus job = mPendingJobs.get(i);
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index 4239248..4fd1350 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -105,6 +105,7 @@
     private final Context mContext;
     private final Object mLock;
     private final IBatteryStats mBatteryStats;
+    private final JobPackageTracker mJobPackageTracker;
     private PowerManager.WakeLock mWakeLock;
 
     // Execution state.
@@ -136,16 +137,18 @@
     /** Track when job will timeout. */
     private long mTimeoutElapsed;
 
-    JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats, Looper looper) {
-        this(service.getContext(), service.getLock(), batteryStats, service, looper);
+    JobServiceContext(JobSchedulerService service, IBatteryStats batteryStats,
+            JobPackageTracker tracker, Looper looper) {
+        this(service.getContext(), service.getLock(), batteryStats, tracker, service, looper);
     }
 
     @VisibleForTesting
     JobServiceContext(Context context, Object lock, IBatteryStats batteryStats,
-                      JobCompletedListener completedListener, Looper looper) {
+            JobPackageTracker tracker, JobCompletedListener completedListener, Looper looper) {
         mContext = context;
         mLock = lock;
         mBatteryStats = batteryStats;
+        mJobPackageTracker = tracker;
         mCallbackHandler = new JobServiceHandler(looper);
         mCompletedListener = completedListener;
         mAvailable = true;
@@ -208,6 +211,7 @@
             } catch (RemoteException e) {
                 // Whatever.
             }
+            mJobPackageTracker.noteActive(job);
             mAvailable = false;
             return true;
         }
@@ -580,6 +584,7 @@
                     return;
                 }
                 completedJob = mRunningJob;
+                mJobPackageTracker.noteInactive(completedJob);
                 try {
                     mBatteryStats.noteJobFinish(mRunningJob.getBatteryName(),
                             mRunningJob.getSourceUid());
diff --git a/services/core/java/com/android/server/job/controllers/AppIdleController.java b/services/core/java/com/android/server/job/controllers/AppIdleController.java
index d8490d4..02bc36ca 100644
--- a/services/core/java/com/android/server/job/controllers/AppIdleController.java
+++ b/services/core/java/com/android/server/job/controllers/AppIdleController.java
@@ -22,6 +22,7 @@
 
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
 import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
@@ -41,10 +42,52 @@
     // Singleton factory
     private static Object sCreationLock = new Object();
     private static volatile AppIdleController sController;
-    final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
+    private final JobSchedulerService mJobSchedulerService;
     private final UsageStatsManagerInternal mUsageStatsInternal;
     boolean mAppIdleParoleOn;
 
+    final class GlobalUpdateFunc implements JobStore.JobStatusFunctor {
+        boolean mChanged;
+
+        @Override public void process(JobStatus jobStatus) {
+            String packageName = jobStatus.getSourcePackageName();
+            final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
+                    jobStatus.getSourceUid(), jobStatus.getSourceUserId());
+            if (DEBUG) {
+                Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
+            }
+            if (jobStatus.setAppNotIdleConstraintSatisfied(!appIdle)) {
+                mChanged = true;
+            }
+        }
+    };
+
+    final static class PackageUpdateFunc implements JobStore.JobStatusFunctor {
+        final int mUserId;
+        final String mPackage;
+        final boolean mIdle;
+        boolean mChanged;
+
+        PackageUpdateFunc(int userId, String pkg, boolean idle) {
+            mUserId = userId;
+            mPackage = pkg;
+            mIdle = idle;
+        }
+
+        @Override public void process(JobStatus jobStatus) {
+            if (jobStatus.getSourcePackageName().equals(mPackage)
+                    && jobStatus.getSourceUserId() == mUserId) {
+                if (jobStatus.setAppNotIdleConstraintSatisfied(!mIdle)) {
+                    if (DEBUG) {
+                        Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
+                                + mPackage + " to " + mIdle);
+                    }
+                    mChanged = true;
+                }
+            }
+        }
+    };
+
     public static AppIdleController get(JobSchedulerService service) {
         synchronized (sCreationLock) {
             if (sController == null) {
@@ -55,9 +98,9 @@
         }
     }
 
-    private AppIdleController(StateChangedListener stateChangedListener, Context context,
-            Object lock) {
-        super(stateChangedListener, context, lock);
+    private AppIdleController(JobSchedulerService service, Context context, Object lock) {
+        super(service, context, lock);
+        mJobSchedulerService = service;
         mUsageStatsInternal = LocalServices.getService(UsageStatsManagerInternal.class);
         mAppIdleParoleOn = mUsageStatsInternal.isAppIdleParoleOn();
         mUsageStatsInternal.addAppIdleStateChangeListener(new AppIdleStateChangeListener());
@@ -65,7 +108,6 @@
 
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
-        mTrackedTasks.add(jobStatus);
         String packageName = jobStatus.getSourcePackageName();
         final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
                 jobStatus.getSourceUid(), jobStatus.getSourceUserId());
@@ -78,19 +120,20 @@
 
     @Override
     public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
-        mTrackedTasks.remove(jobStatus);
     }
 
     @Override
-    public void dumpControllerStateLocked(PrintWriter pw) {
+    public void dumpControllerStateLocked(final PrintWriter pw) {
         pw.println("AppIdle");
         pw.println("Parole On: " + mAppIdleParoleOn);
-        for (JobStatus task : mTrackedTasks) {
-            pw.print(task.getSourcePackageName());
-            pw.print(":runnable="
-                    + ((task.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0));
-            pw.print(", ");
-        }
+        mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
+            @Override public void process(JobStatus jobStatus) {
+                pw.print("  ");
+                pw.print(jobStatus.getSourcePackageName());
+                pw.print(": runnable=");
+                pw.println((jobStatus.satisfiedConstraints&JobStatus.CONSTRAINT_APP_NOT_IDLE) != 0);
+            }
+        });
         pw.println();
     }
 
@@ -102,16 +145,10 @@
                 return;
             }
             mAppIdleParoleOn = isAppIdleParoleOn;
-            for (JobStatus task : mTrackedTasks) {
-                String packageName = task.getSourcePackageName();
-                final boolean appIdle = !mAppIdleParoleOn && mUsageStatsInternal.isAppIdle(packageName,
-                        task.getSourceUid(), task.getSourceUserId());
-                if (DEBUG) {
-                    Slog.d(LOG_TAG, "Setting idle state of " + packageName + " to " + appIdle);
-                }
-                if (task.setAppNotIdleConstraintSatisfied(!appIdle)) {
-                    changed = true;
-                }
+            GlobalUpdateFunc update = new GlobalUpdateFunc();
+            mJobSchedulerService.getJobStore().forEachJob(update);
+            if (update.mChanged) {
+                changed = true;
             }
         }
         if (changed) {
@@ -128,17 +165,10 @@
                 if (mAppIdleParoleOn) {
                     return;
                 }
-                for (JobStatus task : mTrackedTasks) {
-                    if (task.getSourcePackageName().equals(packageName)
-                            && task.getSourceUserId() == userId) {
-                        if (task.setAppNotIdleConstraintSatisfied(!idle)) {
-                            if (DEBUG) {
-                                Slog.d(LOG_TAG, "App Idle state changed, setting idle state of "
-                                        + packageName + " to " + idle);
-                            }
-                            changed = true;
-                        }
-                    }
+                PackageUpdateFunc update = new PackageUpdateFunc(userId, packageName, idle);
+                mJobSchedulerService.getJobStore().forEachJob(update);
+                if (update.mChanged) {
+                    changed = true;
                 }
             }
             if (changed) {
diff --git a/services/core/java/com/android/server/job/controllers/ContentObserverController.java b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
index b2f1958..c5b1a3d 100644
--- a/services/core/java/com/android/server/job/controllers/ContentObserverController.java
+++ b/services/core/java/com/android/server/job/controllers/ContentObserverController.java
@@ -21,6 +21,7 @@
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
+import android.util.TimeUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
 
@@ -46,12 +47,17 @@
      */
     private static final int MAX_URIS_REPORTED = 50;
 
+    /**
+     * At this point we consider it urgent to schedule the job ASAP.
+     */
+    private static final int URIS_URGENT_THRESHOLD = 40;
+
     private static final Object sCreationLock = new Object();
     private static volatile ContentObserverController sController;
 
     final private List<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     ArrayMap<Uri, ObserverInstance> mObservers = new ArrayMap<>();
-    final Handler mHandler = new Handler();
+    final Handler mHandler;
 
     public static ContentObserverController get(JobSchedulerService taskManagerService) {
         synchronized (sCreationLock) {
@@ -72,6 +78,7 @@
     private ContentObserverController(StateChangedListener stateChangedListener, Context context,
                 Object lock) {
         super(stateChangedListener, context, lock);
+        mHandler = new Handler(context.getMainLooper());
     }
 
     @Override
@@ -113,6 +120,11 @@
             taskStatus.changedUris = null;
             taskStatus.setContentTriggerConstraintSatisfied(havePendingUris);
         }
+        if (lastJob != null && lastJob.contentObserverJobInstance != null) {
+            // And now we can detach the instance state from the last job.
+            lastJob.contentObserverJobInstance.detachLocked();
+            lastJob.contentObserverJobInstance = null;
+        }
     }
 
     @Override
@@ -133,30 +145,33 @@
             boolean forUpdate) {
         if (taskStatus.hasContentTriggerConstraint()) {
             if (taskStatus.contentObserverJobInstance != null) {
-                if (incomingJob != null && taskStatus.contentObserverJobInstance != null
-                        && taskStatus.contentObserverJobInstance.mChangedAuthorities != null) {
-                    // We are stopping this job, but it is going to be replaced by this given
-                    // incoming job.  We want to propagate our state over to it, so we don't
-                    // lose any content changes that had happend since the last one started.
-                    // If there is a previous job associated with the new job, propagate over
-                    // any pending content URI trigger reports.
-                    if (incomingJob.contentObserverJobInstance == null) {
-                        incomingJob.contentObserverJobInstance = new JobInstance(incomingJob);
+                taskStatus.contentObserverJobInstance.unscheduleLocked();
+                if (incomingJob != null) {
+                    if (taskStatus.contentObserverJobInstance != null
+                            && taskStatus.contentObserverJobInstance.mChangedAuthorities != null) {
+                        // We are stopping this job, but it is going to be replaced by this given
+                        // incoming job.  We want to propagate our state over to it, so we don't
+                        // lose any content changes that had happend since the last one started.
+                        // If there is a previous job associated with the new job, propagate over
+                        // any pending content URI trigger reports.
+                        if (incomingJob.contentObserverJobInstance == null) {
+                            incomingJob.contentObserverJobInstance = new JobInstance(incomingJob);
+                        }
+                        incomingJob.contentObserverJobInstance.mChangedAuthorities
+                                = taskStatus.contentObserverJobInstance.mChangedAuthorities;
+                        incomingJob.contentObserverJobInstance.mChangedUris
+                                = taskStatus.contentObserverJobInstance.mChangedUris;
+                        taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
+                        taskStatus.contentObserverJobInstance.mChangedUris = null;
                     }
-                    incomingJob.contentObserverJobInstance.mChangedAuthorities
-                            = taskStatus.contentObserverJobInstance.mChangedAuthorities;
-                    incomingJob.contentObserverJobInstance.mChangedUris
-                            = taskStatus.contentObserverJobInstance.mChangedUris;
-                    taskStatus.contentObserverJobInstance.mChangedAuthorities = null;
-                    taskStatus.contentObserverJobInstance.mChangedUris = null;
+                    // We won't detach the content observers here, because we want to
+                    // allow them to continue monitoring so we don't miss anything...  and
+                    // since we are giving an incomingJob here, we know this will be
+                    // immediately followed by a start tracking of that job.
                 } else {
-                    // We won't do this reset if being called for an update, because
-                    // we know it will be immediately followed by maybeStartTrackingJobLocked...
-                    // and we don't want to lose any content changes in-between.
-                    if (taskStatus.contentObserverJobInstance != null) {
-                        taskStatus.contentObserverJobInstance.detach();
-                        taskStatus.contentObserverJobInstance = null;
-                    }
+                    // But here there is no incomingJob, so nothing coming up, so time to detach.
+                    taskStatus.contentObserverJobInstance.detachLocked();
+                    taskStatus.contentObserverJobInstance = null;
                 }
             }
             mTrackedTasks.remove(taskStatus);
@@ -177,9 +192,9 @@
         }
     }
 
-    class ObserverInstance extends ContentObserver {
+    final class ObserverInstance extends ContentObserver {
         final Uri mUri;
-        final ArrayList<JobInstance> mJobs = new ArrayList<>();
+        final ArraySet<JobInstance> mJobs = new ArraySet<>();
 
         public ObserverInstance(Handler handler, Uri uri) {
             super(handler);
@@ -188,11 +203,10 @@
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
-            boolean reportChange = false;
             synchronized (mLock) {
                 final int N = mJobs.size();
                 for (int i=0; i<N; i++) {
-                    JobInstance inst = mJobs.get(i);
+                    JobInstance inst = mJobs.valueAt(i);
                     if (inst.mChangedUris == null) {
                         inst.mChangedUris = new ArraySet<>();
                     }
@@ -203,26 +217,38 @@
                         inst.mChangedAuthorities = new ArraySet<>();
                     }
                     inst.mChangedAuthorities.add(uri.getAuthority());
-                    if (inst.mJobStatus.setContentTriggerConstraintSatisfied(true)) {
-                        reportChange = true;
-                    }
+                    inst.scheduleLocked();
                 }
             }
-            // Let the scheduler know that state has changed. This may or may not result in an
-            // execution.
-            if (reportChange) {
-                mStateChangedListener.onControllerStateChanged();
-            }
         }
     }
 
-    class JobInstance extends ArrayList<ObserverInstance> {
-        private final JobStatus mJobStatus;
-        private ArraySet<Uri> mChangedUris;
-        private ArraySet<String> mChangedAuthorities;
+    static final class TriggerRunnable implements Runnable {
+        final JobInstance mInstance;
+
+        TriggerRunnable(JobInstance instance) {
+            mInstance = instance;
+        }
+
+        @Override public void run() {
+            mInstance.trigger();
+        }
+    }
+
+    final class JobInstance {
+        final ArrayList<ObserverInstance> mMyObservers = new ArrayList<>();
+        final JobStatus mJobStatus;
+        final Runnable mExecuteRunner;
+        final Runnable mTimeoutRunner;
+        ArraySet<Uri> mChangedUris;
+        ArraySet<String> mChangedAuthorities;
+
+        boolean mTriggerPending;
 
         JobInstance(JobStatus jobStatus) {
             mJobStatus = jobStatus;
+            mExecuteRunner = new TriggerRunnable(this);
+            mTimeoutRunner = new TriggerRunnable(this);
             final JobInfo.TriggerContentUri[] uris = jobStatus.getJob().getTriggerContentUris();
             if (uris != null) {
                 for (JobInfo.TriggerContentUri uri : uris) {
@@ -238,15 +264,54 @@
                                 obs);
                     }
                     obs.mJobs.add(this);
-                    add(obs);
+                    mMyObservers.add(obs);
                 }
             }
         }
 
-        void detach() {
-            final int N = size();
+        void trigger() {
+            boolean reportChange = false;
+            synchronized (mLock) {
+                if (mTriggerPending) {
+                    if (mJobStatus.setContentTriggerConstraintSatisfied(true)) {
+                        reportChange = true;
+                    }
+                    unscheduleLocked();
+                }
+            }
+            // Let the scheduler know that state has changed. This may or may not result in an
+            // execution.
+            if (reportChange) {
+                mStateChangedListener.onControllerStateChanged();
+            }
+        }
+
+        void scheduleLocked() {
+            if (!mTriggerPending) {
+                mTriggerPending = true;
+                mHandler.postDelayed(mTimeoutRunner, mJobStatus.getTriggerContentMaxDelay());
+            }
+            mHandler.removeCallbacks(mExecuteRunner);
+            if (mChangedUris.size() >= URIS_URGENT_THRESHOLD) {
+                // If we start getting near the limit, GO NOW!
+                mHandler.post(mExecuteRunner);
+            } else {
+                mHandler.postDelayed(mExecuteRunner, mJobStatus.getTriggerContentUpdateDelay());
+            }
+        }
+
+        void unscheduleLocked() {
+            if (mTriggerPending) {
+                mHandler.removeCallbacks(mExecuteRunner);
+                mHandler.removeCallbacks(mTimeoutRunner);
+                mTriggerPending = false;
+            }
+        }
+
+        void detachLocked() {
+            final int N = mMyObservers.size();
             for (int i=0; i<N; i++) {
-                final ObserverInstance obs = get(i);
+                final ObserverInstance obs = mMyObservers.get(i);
                 obs.mJobs.remove(this);
                 if (obs.mJobs.size() == 0) {
                     mContext.getContentResolver().unregisterContentObserver(obs);
@@ -259,39 +324,54 @@
     @Override
     public void dumpControllerStateLocked(PrintWriter pw) {
         pw.println("Content.");
+        boolean printed = false;
         Iterator<JobStatus> it = mTrackedTasks.iterator();
-        if (it.hasNext()) {
-            pw.print(String.valueOf(it.next().hashCode()));
-        }
         while (it.hasNext()) {
-            pw.print("," + String.valueOf(it.next().hashCode()));
+            if (!printed) {
+                pw.print("  ");
+                printed = true;
+            } else {
+                pw.print(",");
+            }
+            pw.print(System.identityHashCode(it.next()));
         }
-        pw.println();
+        if (printed) {
+            pw.println();
+        }
         int N = mObservers.size();
         if (N > 0) {
-            pw.println("URIs:");
+            pw.println("  Observers:");
             for (int i = 0; i < N; i++) {
                 ObserverInstance obs = mObservers.valueAt(i);
-                pw.print("  ");
-                pw.print(mObservers.keyAt(i));
-                pw.println(":");
                 pw.print("    ");
-                pw.println(obs);
-                pw.println("    Jobs:");
+                pw.print(mObservers.keyAt(i));
+                pw.print(" (");
+                pw.print(System.identityHashCode(obs));
+                pw.println("):");
+                pw.println("      Jobs:");
                 int M = obs.mJobs.size();
                 for (int j=0; j<M; j++) {
-                    JobInstance inst = obs.mJobs.get(j);
-                    pw.print("      ");
-                    pw.print(inst.hashCode());
+                    JobInstance inst = obs.mJobs.valueAt(j);
+                    pw.print("        ");
+                    pw.print(System.identityHashCode(inst.mJobStatus));
                     if (inst.mChangedAuthorities != null) {
                         pw.println(":");
-                        pw.println("        Changed Authorities:");
+                        if (inst.mTriggerPending) {
+                            pw.print("          Trigger pending: update=");
+                            TimeUtils.formatDuration(
+                                    inst.mJobStatus.getTriggerContentUpdateDelay(), pw);
+                            pw.print(", max=");
+                            TimeUtils.formatDuration(
+                                    inst.mJobStatus.getTriggerContentMaxDelay(), pw);
+                            pw.println();
+                        }
+                        pw.println("          Changed Authorities:");
                         for (int k=0; k<inst.mChangedAuthorities.size(); k++) {
                             pw.print("          ");
                             pw.println(inst.mChangedAuthorities.valueAt(k));
                         }
                         if (inst.mChangedUris != null) {
-                            pw.println("        Changed URIs:");
+                            pw.println("          Changed URIs:");
                             for (int k = 0; k<inst.mChangedUris.size(); k++) {
                                 pw.print("          ");
                                 pw.println(inst.mChangedUris.valueAt(k));
diff --git a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index 64887e8..fe563d2 100644
--- a/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/services/core/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -28,6 +28,7 @@
 import com.android.server.DeviceIdleController;
 import com.android.server.LocalServices;
 import com.android.server.job.JobSchedulerService;
+import com.android.server.job.JobStore;
 import com.android.server.job.StateChangedListener;
 
 import java.io.PrintWriter;
@@ -45,9 +46,9 @@
 
     // Singleton factory
     private static Object sCreationLock = new Object();
-    final ArrayList<JobStatus> mTrackedTasks = new ArrayList<JobStatus>();
     private static DeviceIdleJobsController sController;
 
+    private final JobSchedulerService mJobSchedulerService;
     private final PowerManager mPowerManager;
     private final DeviceIdleController.LocalService mLocalDeviceIdleController;
 
@@ -57,6 +58,12 @@
     private boolean mDeviceIdleMode;
     private int[] mDeviceIdleWhitelistAppIds;
 
+    final JobStore.JobStatusFunctor mUpdateFunctor = new JobStore.JobStatusFunctor() {
+        @Override public void process(JobStatus jobStatus) {
+            updateTaskStateLocked(jobStatus);
+        }
+    };
+
     /**
      * Returns a singleton for the DeviceIdleJobsController
      */
@@ -87,10 +94,11 @@
         }
     };
 
-    private DeviceIdleJobsController(StateChangedListener stateChangedListener, Context context,
+    private DeviceIdleJobsController(JobSchedulerService jobSchedulerService, Context context,
             Object lock) {
-        super(stateChangedListener, context, lock);
+        super(jobSchedulerService, context, lock);
 
+        mJobSchedulerService = jobSchedulerService;
         // Register for device idle mode changes
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
         mLocalDeviceIdleController =
@@ -115,9 +123,7 @@
             }
             mDeviceIdleMode = enabled;
             if (LOG_DEBUG) Slog.d(LOG_TAG, "mDeviceIdleMode=" + mDeviceIdleMode);
-            for (JobStatus task : mTrackedTasks) {
-                updateTaskStateLocked(task);
-            }
+            mJobSchedulerService.getJobStore().forEachJob(mUpdateFunctor);
         }
         // Inform the job scheduler service about idle mode changes
         if (changed) {
@@ -160,25 +166,26 @@
     @Override
     public void maybeStartTrackingJobLocked(JobStatus jobStatus, JobStatus lastJob) {
         synchronized (mLock) {
-            mTrackedTasks.add(jobStatus);
             updateTaskStateLocked(jobStatus);
         }
     }
 
     @Override
     public void maybeStopTrackingJobLocked(JobStatus jobStatus, JobStatus incomingJob, boolean forUpdate) {
-        mTrackedTasks.remove(jobStatus);
     }
 
     @Override
-    public void dumpControllerStateLocked(PrintWriter pw) {
+    public void dumpControllerStateLocked(final PrintWriter pw) {
         pw.println("DeviceIdleJobsController");
-        for (JobStatus task : mTrackedTasks) {
-            pw.print(task.getSourcePackageName());
-            pw.print(":runnable="
-                    + ((task.satisfiedConstraints & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0));
-            pw.print(", ");
-        }
+        mJobSchedulerService.getJobStore().forEachJob(new JobStore.JobStatusFunctor() {
+            @Override public void process(JobStatus jobStatus) {
+                pw.print("  ");
+                pw.print(jobStatus.getSourcePackageName());
+                pw.print(": runnable=");
+                pw.println((jobStatus.satisfiedConstraints
+                        & JobStatus.CONSTRAINT_DEVICE_NOT_DOZING) != 0);
+            }
+        });
         pw.println();
     }
 }
\ No newline at end of file
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 39905d8..dd70758 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -61,6 +61,18 @@
     // Full override: ignore all constraints including API-affecting like connectivity
     public static final int OVERRIDE_FULL = 2;
 
+    /** If not specified, trigger update delay is 10 seconds. */
+    public static final long DEFAULT_TRIGGER_UPDATE_DELAY = 10*1000;
+
+    /** The minimum possible update delay is 1/2 second. */
+    public static final long MIN_TRIGGER_UPDATE_DELAY = 500;
+
+    /** If not specified, trigger maxumum delay is 2 minutes. */
+    public static final long DEFAULT_TRIGGER_MAX_DELAY = 2*60*1000;
+
+    /** The minimum possible update delay is 1 second. */
+    public static final long MIN_TRIGGER_MAX_DELAY = 1000;
+
     final JobInfo job;
     /** Uid of the package requesting this job. */
     final int callingUid;
@@ -320,6 +332,22 @@
         return (requiredConstraints&CONSTRAINT_CONTENT_TRIGGER) != 0;
     }
 
+    public long getTriggerContentUpdateDelay() {
+        long time = job.getTriggerContentUpdateDelay();
+        if (time < 0) {
+            return DEFAULT_TRIGGER_UPDATE_DELAY;
+        }
+        return Math.max(time, MIN_TRIGGER_UPDATE_DELAY);
+    }
+
+    public long getTriggerContentMaxDelay() {
+        long time = job.getTriggerContentMaxDelay();
+        if (time < 0) {
+            return DEFAULT_TRIGGER_MAX_DELAY;
+        }
+        return Math.max(time, MIN_TRIGGER_MAX_DELAY);
+    }
+
     public boolean isPersisted() {
         return job.isPersisted();
     }
@@ -540,6 +568,16 @@
                     pw.print(Integer.toHexString(trig.getFlags()));
                     pw.print(' '); pw.println(trig.getUri());
                 }
+                if (job.getTriggerContentUpdateDelay() >= 0) {
+                    pw.print(prefix); pw.print("  Trigger update delay: ");
+                    TimeUtils.formatDuration(job.getTriggerContentUpdateDelay(), pw);
+                    pw.println();
+                }
+                if (job.getTriggerContentMaxDelay() >= 0) {
+                    pw.print(prefix); pw.print("  Trigger max delay: ");
+                    TimeUtils.formatDuration(job.getTriggerContentMaxDelay(), pw);
+                    pw.println();
+                }
             }
             if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
                 pw.print(prefix); pw.print("  Network type: "); pw.println(job.getNetworkType());
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
index d339f69..5e68f8e 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerShellCommand.java
@@ -329,6 +329,7 @@
             final String ssid = removeDoubleQuotes(config.SSID);
             if (id.equals(ssid)) {
                 final NetworkPolicy policy = newPolicy(ssid);
+                policy.metered = true;
                 Log.i(TAG, "Creating new policy for " + ssid + ": " + policy);
                 final NetworkPolicy[] newPolicies = new NetworkPolicy[policies.length + 1];
                 System.arraycopy(policies, 0, newPolicies, 0, policies.length);
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index c19b51f..62fe70c 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -16,7 +16,7 @@
 
 package com.android.server.notification;
 
-import android.app.AutomaticZenRule;
+import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -29,7 +29,6 @@
 import android.provider.Settings;
 import android.service.notification.Condition;
 import android.service.notification.ConditionProviderService;
-import android.service.notification.IConditionListener;
 import android.service.notification.IConditionProvider;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -82,6 +81,7 @@
         c.caption = "condition provider";
         c.serviceInterface = ConditionProviderService.SERVICE_INTERFACE;
         c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES;
+        c.secondarySettingName = Settings.Secure.ENABLED_NOTIFICATION_LISTENERS;
         c.bindPermission = android.Manifest.permission.BIND_CONDITION_PROVIDER_SERVICE;
         c.settingsAction = Settings.ACTION_CONDITION_PROVIDER_SETTINGS;
         c.clientLabel = R.string.condition_provider_service_binding_label;
@@ -257,7 +257,7 @@
     }
 
     @Override
-    protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+    protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
             int userId) {
         final ContentResolver cr = mContext.getContentResolver();
         String settingValue = Settings.Secure.getStringForUser(
@@ -265,12 +265,17 @@
                 settingName,
                 userId);
         if (TextUtils.isEmpty(settingValue))
-            return null;
+            return new ArraySet<>();
         String[] packages = settingValue.split(ENABLED_SERVICES_SEPARATOR);
         ArraySet<ComponentName> result = new ArraySet<>(packages.length);
         for (int i = 0; i < packages.length; i++) {
             if (!TextUtils.isEmpty(packages[i])) {
-                result.addAll(queryPackageForServices(packages[i], userId));
+                final ComponentName component = ComponentName.unflattenFromString(packages[i]);
+                if (component != null) {
+                    result.addAll(queryPackageForServices(component.getPackageName(), userId));
+                } else {
+                    result.addAll(queryPackageForServices(packages[i], userId));
+                }
             }
         }
         return result;
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index c31d93e..29e2e44 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -126,7 +126,8 @@
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_SETTING_RESTORED.equals(intent.getAction())) {
                 String element = intent.getStringExtra(Intent.EXTRA_SETTING_NAME);
-                if (Objects.equals(element, mConfig.secureSettingName)) {
+                if (Objects.equals(element, mConfig.secureSettingName)
+                        || Objects.equals(element, mConfig.secondarySettingName)) {
                     String prevValue = intent.getStringExtra(Intent.EXTRA_SETTING_PREVIOUS_VALUE);
                     String newValue = intent.getStringExtra(Intent.EXTRA_SETTING_NEW_VALUE);
                     settingRestored(element, prevValue, newValue, getSendingUserId());
@@ -186,8 +187,8 @@
 
     // By convention, restored settings are replicated to another settings
     // entry, named similarly but with a disambiguation suffix.
-    public static String restoredSettingName(Config config) {
-        return config.secureSettingName + ":restored";
+    public static String restoredSettingName(String setting) {
+        return setting + ":restored";
     }
 
     // The OS has done a restore of this service's saved state.  We clone it to the
@@ -197,14 +198,14 @@
     public void settingRestored(String element, String oldValue, String newValue, int userid) {
         if (DEBUG) Slog.d(TAG, "Restored managed service setting: " + element
                 + " ovalue=" + oldValue + " nvalue=" + newValue);
-        if (mConfig.secureSettingName.equals(element)) {
+        if (mConfig.secureSettingName.equals(element) ||
+                mConfig.secondarySettingName.equals(element)) {
             if (element != null) {
-                mRestored = null;
                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
-                        restoredSettingName(mConfig),
+                        restoredSettingName(element),
                         newValue,
                         userid);
-                updateSettingsAccordingToInstalledServices(userid);
+                updateSettingsAccordingToInstalledServices(element, userid);
                 rebuildRestoredPackages();
             }
         }
@@ -343,21 +344,25 @@
     private void rebuildRestoredPackages() {
         mRestoredPackages.clear();
         mSnoozingForCurrentProfiles.clear();
-        String settingName = restoredSettingName(mConfig);
+        String secureSettingName = restoredSettingName(mConfig.secureSettingName);
+        String secondarySettingName = mConfig.secondarySettingName == null
+                ? null : restoredSettingName(mConfig.secondarySettingName);
         int[] userIds = mUserProfiles.getCurrentProfileIds();
         final int N = userIds.length;
         for (int i = 0; i < N; ++i) {
-            ArraySet<ComponentName> names = loadComponentNamesFromSetting(settingName, userIds[i]);
-            if (names == null)
-                continue;
-            for (ComponentName name: names) {
+            ArraySet<ComponentName> names =
+                    loadComponentNamesFromSetting(secureSettingName, userIds[i]);
+            if (secondarySettingName != null) {
+                names.addAll(loadComponentNamesFromSetting(secondarySettingName, userIds[i]));
+            }
+            for (ComponentName name : names) {
                 mRestoredPackages.add(name.getPackageName());
             }
         }
     }
 
 
-    protected ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
+    protected @NonNull ArraySet<ComponentName> loadComponentNamesFromSetting(String settingName,
             int userId) {
         final ContentResolver cr = mContext.getContentResolver();
         String settingValue = Settings.Secure.getStringForUser(
@@ -365,7 +370,7 @@
             settingName,
             userId);
         if (TextUtils.isEmpty(settingValue))
-            return null;
+            return new ArraySet<>();
         String[] restored = settingValue.split(ENABLED_SERVICES_SEPARATOR);
         ArraySet<ComponentName> result = new ArraySet<>(restored.length);
         for (int i = 0; i < restored.length; i++) {
@@ -405,7 +410,11 @@
         int[] userIds = mUserProfiles.getCurrentProfileIds();
         final int N = userIds.length;
         for (int i = 0; i < N; ++i) {
-            updateSettingsAccordingToInstalledServices(userIds[i]);
+            updateSettingsAccordingToInstalledServices(mConfig.secureSettingName, userIds[i]);
+            if (mConfig.secondarySettingName != null) {
+                updateSettingsAccordingToInstalledServices(
+                        mConfig.secondarySettingName, userIds[i]);
+            }
         }
         rebuildRestoredPackages();
     }
@@ -442,13 +451,13 @@
         return installed;
     }
 
-    private void updateSettingsAccordingToInstalledServices(int userId) {
+    private void updateSettingsAccordingToInstalledServices(String setting, int userId) {
         boolean restoredChanged = false;
         boolean currentChanged = false;
         Set<ComponentName> restored =
-                loadComponentNamesFromSetting(restoredSettingName(mConfig), userId);
+                loadComponentNamesFromSetting(restoredSettingName(setting), userId);
         Set<ComponentName> current =
-                loadComponentNamesFromSetting(mConfig.secureSettingName, userId);
+                loadComponentNamesFromSetting(setting, userId);
         // Load all services for all packages.
         Set<ComponentName> installed = queryPackageForServices(null, userId);
 
@@ -478,13 +487,13 @@
 
         if (currentChanged) {
             if (DEBUG) Slog.v(TAG, "List of  " + getCaption() + " services was updated " + current);
-            storeComponentsToSetting(retained, mConfig.secureSettingName, userId);
+            storeComponentsToSetting(retained, setting, userId);
         }
 
         if (restoredChanged) {
             if (DEBUG) Slog.v(TAG,
                     "List of  " + getCaption() + " restored services was updated " + restored);
-            storeComponentsToSetting(restored, restoredSettingName(mConfig), userId);
+            storeComponentsToSetting(restored, restoredSettingName(setting), userId);
         }
     }
 
@@ -502,6 +511,10 @@
         for (int i = 0; i < nUserIds; ++i) {
             componentsByUser.put(userIds[i],
                     loadComponentNamesFromSetting(mConfig.secureSettingName, userIds[i]));
+            if (mConfig.secondarySettingName != null) {
+                componentsByUser.get(userIds[i]).addAll(
+                        loadComponentNamesFromSetting(mConfig.secondarySettingName, userIds[i]));
+            }
         }
 
         final ArrayList<ManagedServiceInfo> removableBoundServices = new ArrayList<>();
@@ -522,7 +535,7 @@
                 // decode the list of components
                 final ArraySet<ComponentName> userComponents = componentsByUser.get(userIds[i]);
                 if (null == userComponents) {
-                    toAdd.put(userIds[i], new HashSet<ComponentName>());
+                    toAdd.put(userIds[i], new ArraySet<ComponentName>());
                     continue;
                 }
 
@@ -775,15 +788,25 @@
 
     private class SettingsObserver extends ContentObserver {
         private final Uri mSecureSettingsUri = Settings.Secure.getUriFor(mConfig.secureSettingName);
+        private final Uri mSecondarySettingsUri;
 
         private SettingsObserver(Handler handler) {
             super(handler);
+            if (mConfig.secondarySettingName != null) {
+                mSecondarySettingsUri = Settings.Secure.getUriFor(mConfig.secondarySettingName);
+            } else {
+                mSecondarySettingsUri = null;
+            }
         }
 
         private void observe() {
             ContentResolver resolver = mContext.getContentResolver();
             resolver.registerContentObserver(mSecureSettingsUri,
                     false, this, UserHandle.USER_ALL);
+            if (mSecondarySettingsUri != null) {
+                resolver.registerContentObserver(mSecondarySettingsUri,
+                        false, this, UserHandle.USER_ALL);
+            }
             update(null);
         }
 
@@ -793,9 +816,9 @@
         }
 
         private void update(Uri uri) {
-            if (uri == null || mSecureSettingsUri.equals(uri)) {
-                if (DEBUG) Slog.d(TAG, "Setting changed: mSecureSettingsUri=" + mSecureSettingsUri +
-                        " / uri=" + uri);
+            if (uri == null || mSecureSettingsUri.equals(uri)
+                    || uri.equals(mSecondarySettingsUri)) {
+                if (DEBUG) Slog.d(TAG, "Setting changed: uri=" + uri);
                 rebindServices(false);
                 rebuildRestoredPackages();
             }
@@ -917,6 +940,7 @@
         public String caption;
         public String serviceInterface;
         public String secureSettingName;
+        public String secondarySettingName;
         public String bindPermission;
         public String settingsAction;
         public int clientLabel;
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 2d3ca1f..cabdced 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2186,16 +2186,18 @@
 
     // Clears the 'fake' auto-bunding summary.
     private void maybeClearAutobundleSummaryLocked(Adjustment adjustment) {
-        if (adjustment.getSignals() != null
-                && adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
+        if (adjustment.getSignals() != null) {
+            Bundle.setDefusable(adjustment.getSignals(), true);
+            if (adjustment.getSignals().containsKey(Adjustment.NEEDS_AUTOGROUPING_KEY)
                 && !adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
-            if (mAutobundledSummaries.containsKey(adjustment.getPackage())) {
-                // Clear summary.
-                final NotificationRecord removed = mNotificationsByKey.get(
-                        mAutobundledSummaries.remove(adjustment.getPackage()));
-                if (removed != null) {
-                    mNotificationList.remove(removed);
-                    cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+                if (mAutobundledSummaries.containsKey(adjustment.getPackage())) {
+                    // Clear summary.
+                    final NotificationRecord removed = mNotificationsByKey.get(
+                            mAutobundledSummaries.remove(adjustment.getPackage()));
+                    if (removed != null) {
+                        mNotificationList.remove(removed);
+                        cancelNotificationLocked(removed, false, REASON_UNAUTOBUNDLED);
+                    }
                 }
             }
         }
@@ -2203,47 +2205,50 @@
 
     // Posts a 'fake' summary for a package that has exceeded the solo-notification limit.
     private void maybeAddAutobundleSummary(Adjustment adjustment) {
-        if (adjustment.getSignals() != null
-                && adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
-            final String newAutoBundleKey =
-                    adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
-            int userId = -1;
-            NotificationRecord summaryRecord = null;
-            synchronized (mNotificationList) {
-                if (!mAutobundledSummaries.containsKey(adjustment.getPackage())
-                        && newAutoBundleKey != null) {
-                    // Add summary
-                    final StatusBarNotification adjustedSbn
-                            = mNotificationsByKey.get(adjustment.getKey()).sbn;
+        if (adjustment.getSignals() != null) {
+            Bundle.setDefusable(adjustment.getSignals(), true);
+            if (adjustment.getSignals().getBoolean(Adjustment.NEEDS_AUTOGROUPING_KEY, false)) {
+                final String newAutoBundleKey =
+                        adjustment.getSignals().getString(Adjustment.GROUP_KEY_OVERRIDE_KEY, null);
+                int userId = -1;
+                NotificationRecord summaryRecord = null;
+                synchronized (mNotificationList) {
+                    if (!mAutobundledSummaries.containsKey(adjustment.getPackage())
+                            && newAutoBundleKey != null) {
+                        // Add summary
+                        final StatusBarNotification adjustedSbn
+                                = mNotificationsByKey.get(adjustment.getKey()).sbn;
 
-                    final ApplicationInfo appInfo =
-                            adjustedSbn.getNotification().extras.getParcelable(
-                                    Notification.EXTRA_BUILDER_APPLICATION_INFO);
-                    final Bundle extras = new Bundle();
-                    extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
-                    final Notification summaryNotification =
-                            new Notification.Builder(getContext()).setSmallIcon(
-                                    adjustedSbn.getNotification().getSmallIcon())
-                                    .setGroupSummary(true)
-                                    .setGroup(newAutoBundleKey)
-                                    .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
-                                    .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
-                                    .build();
-                    summaryNotification.extras.putAll(extras);
-                    final StatusBarNotification summarySbn =
-                            new StatusBarNotification(adjustedSbn.getPackageName(),
-                                    adjustedSbn.getOpPkg(),
-                                    Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
-                                    adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
-                                    summaryNotification, adjustedSbn.getUser(), newAutoBundleKey,
-                                    System.currentTimeMillis());
-                    summaryRecord = new NotificationRecord(getContext(), summarySbn);
-                    mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey());
-                    userId = adjustedSbn.getUser().getIdentifier();
+                        final ApplicationInfo appInfo =
+                                adjustedSbn.getNotification().extras.getParcelable(
+                                        Notification.EXTRA_BUILDER_APPLICATION_INFO);
+                        final Bundle extras = new Bundle();
+                        extras.putParcelable(Notification.EXTRA_BUILDER_APPLICATION_INFO, appInfo);
+                        final Notification summaryNotification =
+                                new Notification.Builder(getContext()).setSmallIcon(
+                                        adjustedSbn.getNotification().getSmallIcon())
+                                        .setGroupSummary(true)
+                                        .setGroup(newAutoBundleKey)
+                                        .setFlag(Notification.FLAG_AUTOGROUP_SUMMARY, true)
+                                        .setFlag(Notification.FLAG_GROUP_SUMMARY, true)
+                                        .build();
+                        summaryNotification.extras.putAll(extras);
+                        final StatusBarNotification summarySbn =
+                                new StatusBarNotification(adjustedSbn.getPackageName(),
+                                        adjustedSbn.getOpPkg(),
+                                        Integer.MAX_VALUE, Adjustment.GROUP_KEY_OVERRIDE_KEY,
+                                        adjustedSbn.getUid(), adjustedSbn.getInitialPid(),
+                                        summaryNotification, adjustedSbn.getUser(),
+                                        newAutoBundleKey,
+                                        System.currentTimeMillis());
+                        summaryRecord = new NotificationRecord(getContext(), summarySbn);
+                        mAutobundledSummaries.put(adjustment.getPackage(), summarySbn.getKey());
+                        userId = adjustedSbn.getUser().getIdentifier();
+                    }
                 }
-            }
-            if (summaryRecord != null) {
-                mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
+                if (summaryRecord != null) {
+                    mHandler.post(new EnqueueNotificationRunnable(userId, summaryRecord));
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 92b59965..1fb260d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7085,9 +7085,6 @@
             pkgs = PackageManagerServiceUtils.getPackagesForDexopt(mPackages.values(), this);
         }
 
-        UsageStatsManager usageMgr =
-                (UsageStatsManager) mContext.getSystemService(Context.USAGE_STATS_SERVICE);
-
         int curr = 0;
         int total = pkgs.size();
         for (PackageParser.Package pkg : pkgs) {
@@ -7100,13 +7097,6 @@
                 continue;
             }
 
-            if (!causeFirstBoot && usageMgr.isAppInactive(pkg.packageName)) {
-                if (DEBUG_DEXOPT) {
-                    Log.i(TAG, "Skipping update of of idle app " + pkg.packageName);
-                }
-                continue;
-            }
-
             if (DEBUG_DEXOPT) {
                 Log.i(TAG, "Extracting app " + curr + " of " + total + ": " + pkg.packageName);
             }
diff --git a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
index 27077f2..553c5de 100644
--- a/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
+++ b/services/core/java/com/android/server/policy/ImmersiveModeConfirmation.java
@@ -80,8 +80,6 @@
                 .getInteger(R.integer.config_immersive_mode_confirmation_panic);
         mWindowManager = (WindowManager)
                 mContext.getSystemService(Context.WINDOW_SERVICE);
-        mVrManager = (IVrManager) IVrManager.Stub.asInterface(
-                ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
     }
 
     private long getNavBarExitDuration() {
@@ -121,11 +119,18 @@
 
     private boolean getVrMode() {
         boolean vrMode = false;
-        try {
-            vrMode = mVrManager.getVrModeState();
-        } catch (RemoteException ex) { }
+        if (mVrManager == null) {
+            // lazily grab this service since it may not be available at construction time
+            mVrManager = (IVrManager) IVrManager.Stub.asInterface(
+                ServiceManager.getService(VrManagerService.VR_MANAGER_BINDER_SERVICE));
+        }
+        if (mVrManager != null) {
+            try {
+                vrMode = mVrManager.getVrModeState();
+            } catch (RemoteException ex) { }
+        }
         return vrMode;
-    }        
+    }
 
     public void immersiveModeChanged(String pkg, boolean isImmersiveMode,
             boolean userSetupComplete) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 5ce451f..f6f401a 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -318,6 +318,7 @@
     AccessibilityManager mAccessibilityManager;
     BurnInProtectionHelper mBurnInProtectionHelper;
     AppOpsManager mAppOpsManager;
+    private boolean mHasFeatureWatch;
 
     // Vibrator pattern for haptic feedback of a long press.
     long[] mLongPressVibePattern;
@@ -693,6 +694,7 @@
             = new LogDecelerateInterpolator(100, 0);
 
     private final MutableBoolean mTmpBoolean = new MutableBoolean(false);
+
     private static final int MSG_ENABLE_POINTER_LOCATION = 1;
     private static final int MSG_DISABLE_POINTER_LOCATION = 2;
     private static final int MSG_DISPATCH_MEDIA_KEY_WITH_WAKE_LOCK = 3;
@@ -1501,6 +1503,7 @@
         mDreamManagerInternal = LocalServices.getService(DreamManagerInternal.class);
         mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
         mAppOpsManager = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE);
+        mHasFeatureWatch = mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH);
 
         // Init display burn-in protection
         boolean burnInProtectionEnabled = context.getResources().getBoolean(
@@ -3393,7 +3396,9 @@
             IShortcutService shortcutService = mShortcutKeyServices.get(shortcutCode);
             if (shortcutService != null) {
                 try {
-                    shortcutService.notifyShortcutKeyPressed(shortcutCode);
+                    if (isUserSetupComplete()) {
+                        shortcutService.notifyShortcutKeyPressed(shortcutCode);
+                    }
                 } catch (RemoteException e) {
                     mShortcutKeyServices.delete(shortcutCode);
                 }
@@ -5780,9 +5785,14 @@
     }
 
     private boolean shouldDispatchInputWhenNonInteractive() {
-        // Send events to keyguard while the screen is on.
-        if (isKeyguardShowingAndNotOccluded() && mDisplay != null
-                && mDisplay.getState() != Display.STATE_OFF) {
+        final boolean displayOff = (mDisplay == null || mDisplay.getState() == Display.STATE_OFF);
+
+        if (displayOff && !mHasFeatureWatch) {
+            return false;
+        }
+
+        // Send events to keyguard while the screen is on and it's showing.
+        if (isKeyguardShowingAndNotOccluded() && !displayOff) {
             return true;
         }
 
@@ -6695,7 +6705,7 @@
             @Override public void run() {
                 if (mBootMsgDialog == null) {
                     int theme;
-                    if (mContext.getPackageManager().hasSystemFeature(FEATURE_WATCH)) {
+                    if (mHasFeatureWatch) {
                         theme = com.android.internal.R.style.Theme_Micro_Dialog_Alert;
                     } else if (mContext.getPackageManager().hasSystemFeature(FEATURE_TELEVISION)) {
                         theme = com.android.internal.R.style.Theme_Leanback_Dialog_Alert;
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 984fb76..3c84fc2 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -974,7 +974,6 @@
         public void register(Context context) {
             IntentFilter filter = new IntentFilter();
             filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-            filter.addAction(Intent.ACTION_USER_PRESENT);
             filter.addAction(Intent.ACTION_USER_ADDED);
             filter.addAction(Intent.ACTION_USER_REMOVED);
             context.registerReceiverAsUser(this,
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index ca1a7ac..10e30ed 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -128,6 +128,8 @@
         public void onBootPhase(int phase) {
             if (phase == SystemService.PHASE_ACTIVITY_MANAGER_READY) {
                 mService.systemReady();
+            } else if (phase == SystemService.PHASE_THIRD_PARTY_APPS_CAN_START) {
+                mService.switchUser(UserHandle.USER_SYSTEM, null);
             }
         }
 
@@ -850,9 +852,6 @@
                 Slog.i(TAG, "Nondefault wallpaper component; gracefully ignoring");
             }
         }
-        switchWallpaper(wallpaper, null);
-        wallpaper.wallpaperObserver = new WallpaperObserver(wallpaper);
-        wallpaper.wallpaperObserver.startWatching();
 
         IntentFilter userFilter = new IntentFilter();
         userFilter.addAction(Intent.ACTION_USER_REMOVED);
diff --git a/services/core/java/com/android/server/webkit/SystemImpl.java b/services/core/java/com/android/server/webkit/SystemImpl.java
index a5d68da..361f0d4 100644
--- a/services/core/java/com/android/server/webkit/SystemImpl.java
+++ b/services/core/java/com/android/server/webkit/SystemImpl.java
@@ -59,15 +59,22 @@
     private static final String TAG_AVAILABILITY = "availableByDefault";
     private static final String TAG_SIGNATURE = "signature";
     private static final String TAG_FALLBACK = "isFallback";
+    private final WebViewProviderInfo[] mWebViewProviderPackages;
 
-    /**
-     * Returns all packages declared in the framework resources as potential WebView providers.
-     * @hide
-     * */
-    @Override
-    public WebViewProviderInfo[] getWebViewPackages() {
+    // Initialization-on-demand holder idiom for getting the WebView provider packages once and
+    // for all in a thread-safe manner.
+    private static class LazyHolder {
+        private static final SystemImpl INSTANCE = new SystemImpl();
+    }
+
+    public static SystemImpl getInstance() {
+        return LazyHolder.INSTANCE;
+    }
+
+    private SystemImpl() {
         int numFallbackPackages = 0;
         int numAvailableByDefaultPackages = 0;
+        int numAvByDefaultAndNotFallback = 0;
         XmlResourceParser parser = null;
         List<WebViewProviderInfo> webViewProviders = new ArrayList<WebViewProviderInfo>();
         try {
@@ -111,6 +118,9 @@
                     }
                     if (currentProvider.availableByDefault) {
                         numAvailableByDefaultPackages++;
+                        if (!currentProvider.isFallback) {
+                            numAvByDefaultAndNotFallback++;
+                        }
                     }
                     webViewProviders.add(currentProvider);
                 }
@@ -127,7 +137,20 @@
             throw new AndroidRuntimeException("There must be at least one WebView package "
                     + "that is available by default");
         }
-        return webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+        if (numAvByDefaultAndNotFallback == 0) {
+            throw new AndroidRuntimeException("There must be at least one WebView package "
+                    + "that is available by default and not a fallback");
+        }
+        mWebViewProviderPackages =
+                webViewProviders.toArray(new WebViewProviderInfo[webViewProviders.size()]);
+    }
+    /**
+     * Returns all packages declared in the framework resources as potential WebView providers.
+     * @hide
+     * */
+    @Override
+    public WebViewProviderInfo[] getWebViewPackages() {
+        return mWebViewProviderPackages;
     }
 
     public int getFactoryPackageVersion(String packageName) throws NameNotFoundException {
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateService.java b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
index bbb4951..9b971e0 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateService.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateService.java
@@ -55,7 +55,7 @@
 
     public WebViewUpdateService(Context context) {
         super(context);
-        mImpl = new WebViewUpdateServiceImpl(context, new SystemImpl());
+        mImpl = new WebViewUpdateServiceImpl(context, SystemImpl.getInstance());
     }
 
     @Override
diff --git a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
index e17ea49..d90d922 100644
--- a/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
+++ b/services/core/java/com/android/server/webkit/WebViewUpdateServiceImpl.java
@@ -291,6 +291,13 @@
             try {
                 synchronized(mLock) {
                     mCurrentWebViewPackage = findPreferredWebViewPackage();
+                    // Don't persist the user-chosen setting across boots if the package being
+                    // chosen is not used (could be disabled or uninstalled) so that the user won't
+                    // be surprised by the device switching to using a certain webview package,
+                    // that was uninstalled/disabled a long time ago, if it is installed/enabled
+                    // again.
+                    mSystemInterface.updateUserSetting(mContext,
+                            mCurrentWebViewPackage.packageName);
                     onWebViewProviderChanged(mCurrentWebViewPackage);
                 }
             } catch (Throwable t) {
@@ -301,38 +308,42 @@
 
         /**
          * Change WebView provider and provider setting and kill packages using the old provider.
-         * Return the new provider (in case we are in the middle of creating relro files this new
-         * provider will not be in use directly, but will when the relros are done).
+         * Return the new provider (in case we are in the middle of creating relro files, or
+         * replacing that provider it will not be in use directly, but will be used when the relros
+         * or the replacement are done).
          */
         public String changeProviderAndSetting(String newProviderName) {
             PackageInfo oldPackage = null;
             PackageInfo newPackage = null;
+            boolean providerChanged = false;
             synchronized(mLock) {
                 oldPackage = mCurrentWebViewPackage;
                 mSystemInterface.updateUserSetting(mContext, newProviderName);
 
                 try {
                     newPackage = findPreferredWebViewPackage();
-                    if (oldPackage != null
-                            && newPackage.packageName.equals(oldPackage.packageName)) {
-                        // If we don't perform the user change, revert the settings change.
-                        mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
-                        return newPackage.packageName;
-                    }
+                    providerChanged = (oldPackage == null)
+                            || !newPackage.packageName.equals(oldPackage.packageName);
                 } catch (WebViewFactory.MissingWebViewPackageException e) {
                     Slog.e(TAG, "Tried to change WebView provider but failed to fetch WebView " +
                             "package " + e);
                     // If we don't perform the user change but don't have an installed WebView
                     // package, we will have changed the setting and it will be used when a package
                     // is available.
-                    return newProviderName;
+                    return "";
                 }
-                onWebViewProviderChanged(newPackage);
+                // Perform the provider change if we chose a new provider
+                if (providerChanged) {
+                    onWebViewProviderChanged(newPackage);
+                }
             }
-            // Kill apps using the old provider
-            if (oldPackage != null) {
+            // Kill apps using the old provider only if we changed provider
+            if (providerChanged && oldPackage != null) {
                 mSystemInterface.killPackageDependents(oldPackage.packageName);
             }
+            // Return the new provider, this is not necessarily the one we were asked to switch to
+            // But the persistent setting will now be pointing to the provider we were asked to
+            // switch to anyway
             return newPackage.packageName;
         }
 
@@ -345,7 +356,6 @@
                 mAnyWebViewInstalled = true;
                 if (mNumRelroCreationsStarted == mNumRelroCreationsFinished) {
                     mCurrentWebViewPackage = newPackage;
-                    mSystemInterface.updateUserSetting(mContext, newPackage.packageName);
 
                     // The relro creations might 'finish' (not start at all) before
                     // WebViewFactory.onWebViewProviderChanged which means we might not know the
@@ -394,7 +404,7 @@
         }
 
 
-        private class ProviderAndPackageInfo {
+        private static class ProviderAndPackageInfo {
             public final WebViewProviderInfo provider;
             public final PackageInfo packageInfo;
 
@@ -432,9 +442,12 @@
                 }
             }
 
-            // Could not find any enabled package either, use the most stable provider.
+            // Could not find any enabled package either, use the most stable and default-available
+            // provider.
             for (ProviderAndPackageInfo providerAndPackage : providers) {
-                return providerAndPackage.packageInfo;
+                if (providerAndPackage.provider.availableByDefault) {
+                    return providerAndPackage.packageInfo;
+                }
             }
 
             mAnyWebViewInstalled = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 57f38d1..57dc97a 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -18,6 +18,7 @@
 
 import android.Manifest;
 import android.animation.ValueAnimator;
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
@@ -153,6 +154,8 @@
 import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.net.Socket;
 import java.text.DateFormat;
 import java.util.ArrayList;
@@ -332,6 +335,14 @@
 
     private static final String PROPERTY_BUILD_DATE_UTC = "ro.build.date.utc";
 
+    // Enums for animation scale update types.
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({WINDOW_ANIMATION_SCALE, TRANSITION_ANIMATION_SCALE, ANIMATION_DURATION_SCALE})
+    private @interface UpdateAnimationScaleMode {};
+    private static final int WINDOW_ANIMATION_SCALE = 0;
+    private static final int TRANSITION_ANIMATION_SCALE = 1;
+    private static final int ANIMATION_DURATION_SCALE = 2;
+
     final private KeyguardDisableHandler mKeyguardDisableHandler;
 
     final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -613,18 +624,42 @@
     private final class SettingsObserver extends ContentObserver {
         private final Uri mDisplayInversionEnabledUri =
                 Settings.Secure.getUriFor(Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
+        private final Uri mWindowAnimationScaleUri =
+                Settings.Global.getUriFor(Settings.Global.WINDOW_ANIMATION_SCALE);
+        private final Uri mTransitionAnimationScaleUri =
+                Settings.Global.getUriFor(Settings.Global.TRANSITION_ANIMATION_SCALE);
+        private final Uri mAnimationDurationScaleUri =
+                Settings.Global.getUriFor(Settings.Global.ANIMATOR_DURATION_SCALE);
 
         public SettingsObserver() {
             super(new Handler());
             ContentResolver resolver = mContext.getContentResolver();
             resolver.registerContentObserver(mDisplayInversionEnabledUri, false, this,
                     UserHandle.USER_ALL);
+            resolver.registerContentObserver(mWindowAnimationScaleUri, false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(mTransitionAnimationScaleUri, false, this,
+                    UserHandle.USER_ALL);
+            resolver.registerContentObserver(mAnimationDurationScaleUri, false, this,
+                    UserHandle.USER_ALL);
         }
 
         @Override
         public void onChange(boolean selfChange, Uri uri) {
             if (mDisplayInversionEnabledUri.equals(uri)) {
                 updateCircularDisplayMaskIfNeeded();
+            } else {
+                @UpdateAnimationScaleMode
+                final int mode;
+                if (uri.equals(mWindowAnimationScaleUri)) {
+                    mode = WINDOW_ANIMATION_SCALE;
+                } else if (uri.equals(mTransitionAnimationScaleUri)) {
+                    mode = TRANSITION_ANIMATION_SCALE;
+                } else { // uri.equals(mAnimationDurationScaleUri)
+                    mode = ANIMATION_DURATION_SCALE;
+                }
+                Message m = mH.obtainMessage(H.UPDATE_ANIMATION_SCALE, mode, 0);
+                mH.sendMessage(m);
             }
         }
     }
@@ -2072,6 +2107,11 @@
             if (win.isVisibleOrAdding() && updateOrientationFromAppTokensLocked(false)) {
                 reportNewConfig = true;
             }
+            if (attrs.removeTimeoutMilliseconds > 0) {
+                mH.sendMessageDelayed(
+                        mH.obtainMessage(H.WINDOW_REMOVE_TIMEOUT, win),
+                        attrs.removeTimeoutMilliseconds);
+            }
         }
 
         if (reportNewConfig) {
@@ -3905,16 +3945,6 @@
                 return;
             }
 
-            if (transferStartingWindow(transferFrom, wtoken)) {
-                return;
-            }
-
-            // There is no existing starting window, and the caller doesn't
-            // want us to create one, so that's it!
-            if (!createIfNeeded) {
-                return;
-            }
-
             // If this is a translucent window, then don't
             // show a starting window -- the current effect (a full-screen
             // opaque starting window that fades away to the real contents
@@ -3960,6 +3990,16 @@
                 }
             }
 
+            if (transferStartingWindow(transferFrom, wtoken)) {
+                return;
+            }
+
+            // There is no existing starting window, and the caller doesn't
+            // want us to create one, so that's it!
+            if (!createIfNeeded) {
+                return;
+            }
+
             if (DEBUG_STARTING_WINDOW) Slog.v(TAG_WM, "Creating StartingData");
             wtoken.startingData = new StartingData(pkg, theme, compatInfo, nonLocalizedLabel,
                     labelRes, icon, logo, windowFlags);
@@ -5986,7 +6026,13 @@
                 "screenshotApplications()")) {
             throw new SecurityException("Requires READ_FRAME_BUFFER permission");
         }
-        return screenshotApplicationsInner(appToken, displayId, width, height, false, frameScale);
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "screenshotApplications");
+            return screenshotApplicationsInner(appToken, displayId, width, height, false,
+                    frameScale);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_WINDOW_MANAGER);
+        }
     }
 
     Bitmap screenshotApplicationsInner(IBinder appToken, int displayId, int width, int height,
@@ -7747,6 +7793,8 @@
         public static final int NOTIFY_APP_TRANSITION_CANCELLED = 48;
         public static final int NOTIFY_APP_TRANSITION_FINISHED = 49;
         public static final int NOTIFY_STARTING_WINDOW_DRAWN = 50;
+        public static final int UPDATE_ANIMATION_SCALE = 51;
+        public static final int WINDOW_REMOVE_TIMEOUT = 52;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -8030,6 +8078,36 @@
                     break;
                 }
 
+                case UPDATE_ANIMATION_SCALE: {
+                    @UpdateAnimationScaleMode
+                    final int mode = msg.arg1;
+                    switch (mode) {
+                        case WINDOW_ANIMATION_SCALE: {
+                            mWindowAnimationScaleSetting = Settings.Global.getFloat(
+                                    mContext.getContentResolver(),
+                                    Settings.Global.WINDOW_ANIMATION_SCALE,
+                                    mWindowAnimationScaleSetting);
+                            break;
+                        }
+                        case TRANSITION_ANIMATION_SCALE: {
+                            mTransitionAnimationScaleSetting = Settings.Global.getFloat(
+                                    mContext.getContentResolver(),
+                                    Settings.Global.TRANSITION_ANIMATION_SCALE,
+                                    mTransitionAnimationScaleSetting);
+                            break;
+                        }
+                        case ANIMATION_DURATION_SCALE: {
+                            mAnimatorDurationScaleSetting = Settings.Global.getFloat(
+                                    mContext.getContentResolver(),
+                                    Settings.Global.ANIMATOR_DURATION_SCALE,
+                                    mAnimatorDurationScaleSetting);
+                            dispatchNewAnimatorScaleLocked(null);
+                            break;
+                        }
+                    }
+                    break;
+                }
+
                 case FORCE_GC: {
                     synchronized (mWindowMap) {
                         // Since we're holding both mWindowMap and mAnimator we don't need to
@@ -8329,6 +8407,18 @@
                     mAmInternal.notifyStartingWindowDrawn();
                 }
                 break;
+                case WINDOW_REMOVE_TIMEOUT: {
+                    final WindowState window = (WindowState) msg.obj;
+                    synchronized(mWindowMap) {
+                        // It's counterintuitive that we check that "mWindowRemovalAllowed"
+                        // is false. But in fact if it's true, it means a remove has already
+                        // been requested and we better just not do anything.
+                        if (!window.mRemoved && !window.mWindowRemovalAllowed) {
+                            removeWindowLocked(window);
+                        }
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index c48d7d1..8371cfe 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -2410,8 +2410,8 @@
             pw.print(prefix); pw.print("mToken="); pw.println(mToken);
             pw.print(prefix); pw.print("mRootToken="); pw.println(mRootToken);
             if (mAppToken != null) {
-                pw.print(prefix); pw.print("mAppToken="); pw.print(mAppToken);
-                pw.print(" isAnimatingWithSavedSurface()=");
+                pw.print(prefix); pw.print("mAppToken="); pw.println(mAppToken);
+                pw.print(prefix); pw.print(" isAnimatingWithSavedSurface()=");
                 pw.print(isAnimatingWithSavedSurface());
                 pw.print(" mAppDied=");pw.println(mAppDied);
             }
@@ -2496,6 +2496,7 @@
                     pw.print(" content="); mContentInsets.printShortString(pw);
                     pw.print(" visible="); mVisibleInsets.printShortString(pw);
                     pw.print(" stable="); mStableInsets.printShortString(pw);
+                    pw.print(" surface="); mAttrs.surfaceInsets.printShortString(pw);
                     pw.print(" outsets="); mOutsets.printShortString(pw);
                     pw.println();
             pw.print(prefix); pw.print("Lst insets: overscan=");
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 140f381..0245513 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.StackId;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
 import static android.view.WindowManager.LayoutParams.FLAG_SCALED;
@@ -1032,7 +1033,7 @@
                         // relative to their containing frame. We need to offset the difference
                         // between the containing frame as used to calculate the crop and our
                         // bounds to compensate for this.
-                        if (mWin.isChildWindow() && mWin.layoutInParentFrame()) {
+                        if (mWin.layoutInParentFrame()) {
                             mClipRect.offset( (mWin.mContainingFrame.left - mWin.mFrame.left),
                                     mWin.mContainingFrame.top - mWin.mFrame.top );
                         }
@@ -1164,8 +1165,8 @@
             final float scale = w.mInvGlobalScale;
             mSystemDecorRect.left = (int) (mSystemDecorRect.left * scale - 0.5f);
             mSystemDecorRect.top = (int) (mSystemDecorRect.top * scale - 0.5f);
-            mSystemDecorRect.right = (int) ((mSystemDecorRect.right+1) * scale - 0.5f);
-            mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom+1) * scale - 0.5f);
+            mSystemDecorRect.right = (int) ((mSystemDecorRect.right + 1) * scale - 0.5f);
+            mSystemDecorRect.bottom = (int) ((mSystemDecorRect.bottom + 1) * scale - 0.5f);
         }
     }
 
@@ -1178,8 +1179,8 @@
             return;
         }
         final DisplayInfo displayInfo = displayContent.getDisplayInfo();
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Updating crop for window: " + w + ", " + "mLastCrop=" +
-                mLastClipRect);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+                "Updating crop win=" + w + " mLastCrop=" + mLastClipRect);
 
         // Need to recompute a new system decor rect each time.
         if (!w.isDefaultDisplay()) {
@@ -1204,8 +1205,8 @@
         } else {
             // Crop to the system decor specified by policy.
             calculateSystemDecorRect();
-            if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop for " + w + ", mDecorFrame="
-                    + w.mDecorFrame + ", mSystemDecorRect=" + mSystemDecorRect);
+            if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Applying decor to crop win=" + w + " mDecorFrame="
+                    + w.mDecorFrame + " mSystemDecorRect=" + mSystemDecorRect);
         }
 
         final boolean fullscreen = w.isFrameFullscreen(displayInfo);
@@ -1215,8 +1216,8 @@
         // We use the clip rect as provided by the tranformation for non-fullscreen windows to
         // avoid premature clipping with the system decor rect.
         clipRect.set((mHasClipRect && !fullscreen) ? mClipRect : mSystemDecorRect);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Initial clip rect: " + clipRect + ", mHasClipRect="
-                + mHasClipRect + ", fullscreen=" + fullscreen);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "win=" + w + " Initial clip rect: " + clipRect
+                + " mHasClipRect=" + mHasClipRect + " fullscreen=" + fullscreen);
 
         if (isFreeformResizing && !w.isChildWindow()) {
             // For freeform resizing non child windows, we are using the big surface positioned
@@ -1243,7 +1244,8 @@
 
         finalClipRect.setEmpty();
         adjustCropToStackBounds(w, clipRect, finalClipRect, isFreeformResizing);
-        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "Clip rect after stack adjustment=" + clipRect);
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG,
+                "win=" + w + " Clip rect after stack adjustment=" + clipRect);
 
         w.transformFromScreenToSurfaceSpace(clipRect);
 
@@ -1254,6 +1256,8 @@
     }
 
     void updateSurfaceWindowCrop(Rect clipRect, Rect finalClipRect, boolean recoveringMemory) {
+        if (DEBUG_WINDOW_CROP) Slog.d(TAG, "updateSurfaceWindowCrop: win=" + mWin
+                + " clipRect=" + clipRect + " finalClipRect=" + finalClipRect);
         if (!clipRect.equals(mLastClipRect)) {
             mLastClipRect.set(clipRect);
             mSurfaceController.setCropInTransaction(clipRect, recoveringMemory);
@@ -1294,13 +1298,14 @@
 
         final TaskStack stack = task.mStack;
         stack.getDimBounds(mTmpStackBounds);
+        final Rect surfaceInsets = w.getAttrs().surfaceInsets;
         // When we resize we use the big surface approach, which means we can't trust the
         // window frame bounds anymore. Instead, the window will be placed at 0, 0, but to avoid
         // hardcoding it, we use surface coordinates.
         final int frameX = isFreeformResizing ? (int) mSurfaceController.getX() :
-                w.mFrame.left + mWin.mXOffset - w.getAttrs().surfaceInsets.left;
+                w.mFrame.left + mWin.mXOffset - surfaceInsets.left;
         final int frameY = isFreeformResizing ? (int) mSurfaceController.getY() :
-                w.mFrame.top + mWin.mYOffset - w.getAttrs().surfaceInsets.top;
+                w.mFrame.top + mWin.mYOffset - surfaceInsets.top;
 
         // If we are animating, we either apply the clip before applying all the animation
         // transformation or after all the transformation.
@@ -1311,6 +1316,15 @@
         if (useFinalClipRect) {
             finalClipRect.set(mTmpStackBounds);
         } else {
+            if (StackId.hasWindowShadow(stack.mStackId)
+                    && !StackId.isTaskResizeAllowed(stack.mStackId)) {
+                // The windows in this stack display drop shadows and the fill the entire stack
+                // area. Adjust the stack bounds we will use to cropping take into account the
+                // offsets we use to display the drop shadow so it doesn't get cropped.
+                mTmpStackBounds.inset(-surfaceInsets.left, -surfaceInsets.top,
+                        -surfaceInsets.right, -surfaceInsets.bottom);
+            }
+
             clipRect.left = Math.max(0,
                     Math.max(mTmpStackBounds.left, frameX + clipRect.left) - frameX);
             clipRect.top = Math.max(0,
@@ -1356,21 +1370,19 @@
             // past where the system would have cropped us
             mTmpClipRect.set(0, 0, mTmpSize.width(), mTmpSize.height());
             mTmpFinalClipRect.setEmpty();
-            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
         } else {
             mSurfaceController.setPositionInTransaction(mTmpSize.left, mTmpSize.top,
                     recoveringMemory);
-            updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
         }
 
+        updateSurfaceWindowCrop(mTmpClipRect, mTmpFinalClipRect, recoveringMemory);
 
         mSurfaceController.setMatrixInTransaction(mDsDx * w.mHScale * extraHScale,
                 mDtDx * w.mVScale * extraVScale,
                 mDsDy * w.mHScale * extraHScale,
                 mDtDy * w.mVScale * extraVScale, recoveringMemory);
         mSurfaceResized = mSurfaceController.setSizeInTransaction(
-                mTmpSize.width(), mTmpSize.height(),
-                recoveringMemory);
+                mTmpSize.width(), mTmpSize.height(), recoveringMemory);
 
         if (mSurfaceResized) {
             mReportSurfaceResized = true;
@@ -1775,7 +1787,7 @@
             pw.print(prefix); pw.print("mAnimating="); pw.print(mAnimating);
                     pw.print(" mLocalAnimating="); pw.print(mLocalAnimating);
                     pw.print(" mAnimationIsEntrance="); pw.print(mAnimationIsEntrance);
-                    pw.print(" mAnimation="); pw.println(mAnimation);
+                    pw.print(" mAnimation="); pw.print(mAnimation);
                     pw.print(" mStackClip="); pw.println(mStackClip);
         }
         if (mHasTransformation || mHasLocalTransformation) {
@@ -1793,9 +1805,9 @@
             pw.print(prefix); pw.print(" mLastHidden="); pw.println(mLastHidden);
             pw.print(prefix); pw.print("mSystemDecorRect="); mSystemDecorRect.printShortString(pw);
             pw.print(" last="); mLastSystemDecorRect.printShortString(pw);
-            if (mHasClipRect) {
-                pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
-            }
+            pw.print(" mHasClipRect="); pw.print(mHasClipRect);
+            pw.print(" mLastClipRect="); mLastClipRect.printShortString(pw);
+
             if (!mLastFinalClipRect.isEmpty()) {
                 pw.print(" mLastFinalClipRect="); mLastFinalClipRect.printShortString(pw);
             }
diff --git a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
index 93eb82f..058b631 100644
--- a/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
+++ b/services/core/jni/com_android_server_location_GnssLocationProvider.cpp
@@ -1165,7 +1165,7 @@
 
 static jobject translate_gnss_clock(JNIEnv* env, GnssClock* clock) {
     JavaObject object(env, "android/location/GnssClock");
-    GpsClockFlags flags = clock->flags;
+    GnssClockFlags flags = clock->flags;
 
     SET_IF(GNSS_CLOCK_HAS_LEAP_SECOND,
            LeapSecond,
@@ -1237,9 +1237,10 @@
 static jobject translate_gnss_measurement(JNIEnv* env,
                                           GnssMeasurement* measurement) {
     JavaObject object(env, "android/location/GnssMeasurement");
-    GpsMeasurementFlags flags = measurement->flags;
 
-    SET(Svid, measurement->svid);
+    GnssMeasurementFlags flags = measurement->flags;
+
+    SET(Svid, static_cast<int32_t>(measurement->svid));
     SET(ConstellationType, static_cast<int32_t>(measurement->constellation));
     SET(TimeOffsetNanos, measurement->time_offset_ns);
     SET(State, static_cast<int32_t>(measurement->state));
@@ -1379,8 +1380,8 @@
         ALOGE("Invalid data provided to gps_measurement_callback");
         return;
     }
-    if (data->size != sizeof(GpsData)) {
-        ALOGE("Invalid GpsData size found in gps_measurement_callback, "
+    if (data->size != sizeof(GnssData)) {
+        ALOGE("Invalid GnssData size found in gnss_measurement_callback, "
               "size=%zd",
               data->size);
         return;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 0454b00..d3d05f3 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -655,8 +655,8 @@
         Bundle userRestrictions;
 
         // Support text provided by the admin to display to the user.
-        String shortSupportMessage = null;
-        String longSupportMessage = null;
+        CharSequence shortSupportMessage = null;
+        CharSequence longSupportMessage = null;
 
         // Background color of confirm credentials screen. Default: teal.
         static final int DEF_ORGANIZATION_COLOR = Color.parseColor("#00796B");
@@ -870,12 +870,12 @@
             }
             if (!TextUtils.isEmpty(shortSupportMessage)) {
                 out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
-                out.text(shortSupportMessage);
+                out.text(shortSupportMessage.toString());
                 out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
             }
             if (!TextUtils.isEmpty(longSupportMessage)) {
                 out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
-                out.text(longSupportMessage);
+                out.text(longSupportMessage.toString());
                 out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
             }
             if (parentAdmin != null) {
@@ -8504,7 +8504,7 @@
     }
 
     @Override
-    public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+    public void setShortSupportMessage(@NonNull ComponentName who, CharSequence message) {
         if (!mHasFeature) {
             return;
         }
@@ -8521,7 +8521,7 @@
     }
 
     @Override
-    public String getShortSupportMessage(@NonNull ComponentName who) {
+    public CharSequence getShortSupportMessage(@NonNull ComponentName who) {
         if (!mHasFeature) {
             return null;
         }
@@ -8534,7 +8534,7 @@
     }
 
     @Override
-    public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+    public void setLongSupportMessage(@NonNull ComponentName who, CharSequence message) {
         if (!mHasFeature) {
             return;
         }
@@ -8551,7 +8551,7 @@
     }
 
     @Override
-    public String getLongSupportMessage(@NonNull ComponentName who) {
+    public CharSequence getLongSupportMessage(@NonNull ComponentName who) {
         if (!mHasFeature) {
             return null;
         }
@@ -8564,7 +8564,7 @@
     }
 
     @Override
-    public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+    public CharSequence getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
         if (!mHasFeature) {
             return null;
         }
@@ -8582,7 +8582,7 @@
     }
 
     @Override
-    public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+    public CharSequence getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
         if (!mHasFeature) {
             return null;
         }
diff --git a/services/net/java/android/net/dhcp/DhcpClient.java b/services/net/java/android/net/dhcp/DhcpClient.java
index 406dd56..804fa03 100644
--- a/services/net/java/android/net/dhcp/DhcpClient.java
+++ b/services/net/java/android/net/dhcp/DhcpClient.java
@@ -336,17 +336,17 @@
     class ReceiveThread extends Thread {
 
         private final byte[] mPacket = new byte[DhcpPacket.MAX_LENGTH];
-        private boolean stopped = false;
+        private volatile boolean mStopped = false;
 
         public void halt() {
-            stopped = true;
+            mStopped = true;
             closeSockets();  // Interrupts the read() call the thread is blocked in.
         }
 
         @Override
         public void run() {
             if (DBG) Log.d(TAG, "Receive thread started");
-            while (!stopped) {
+            while (!mStopped) {
                 int length = 0;  // Or compiler can't tell it's initialized if a parse error occurs.
                 try {
                     length = Os.read(mPacketSock, mPacket, 0, mPacket.length);
@@ -355,7 +355,7 @@
                     if (DBG) Log.d(TAG, "Received packet: " + packet);
                     sendMessage(CMD_RECEIVED_PACKET, packet);
                 } catch (IOException|ErrnoException e) {
-                    if (!stopped) {
+                    if (!mStopped) {
                         Log.e(TAG, "Read error", e);
                     }
                     DhcpClientEvent.logEvent(IpConnectivityEvent.IPCE_DHCP_RECV_ERROR,
diff --git a/services/net/java/android/net/dhcp/DhcpPacket.java b/services/net/java/android/net/dhcp/DhcpPacket.java
index a881408..b184fe5 100644
--- a/services/net/java/android/net/dhcp/DhcpPacket.java
+++ b/services/net/java/android/net/dhcp/DhcpPacket.java
@@ -3,6 +3,7 @@
 import android.net.DhcpResults;
 import android.net.LinkAddress;
 import android.net.NetworkUtils;
+import android.net.metrics.DhcpErrorEvent;
 import android.os.Build;
 import android.os.SystemProperties;
 import android.system.OsConstants;
@@ -765,6 +766,7 @@
         // check to see if we need to parse L2, IP, and UDP encaps
         if (pktType == ENCAP_L2) {
             if (packet.remaining() < MIN_PACKET_LENGTH_L2) {
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_TOO_SHORT);
                 throw new ParseException("L2 packet too short, %d < %d",
                         packet.remaining(), MIN_PACKET_LENGTH_L2);
             }
@@ -777,13 +779,16 @@
 
             short l2type = packet.getShort();
 
-            if (l2type != OsConstants.ETH_P_IP)
+            if (l2type != OsConstants.ETH_P_IP) {
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.L2_WRONG_ETH_TYPE);
                 throw new ParseException("Unexpected L2 type 0x%04x, expected 0x%04x",
                         l2type, OsConstants.ETH_P_IP);
+            }
         }
 
         if (pktType <= ENCAP_L3) {
             if (packet.remaining() < MIN_PACKET_LENGTH_L3) {
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_TOO_SHORT);
                 throw new ParseException("L3 packet too short, %d < %d",
                         packet.remaining(), MIN_PACKET_LENGTH_L3);
             }
@@ -791,6 +796,7 @@
             byte ipTypeAndLength = packet.get();
             int ipVersion = (ipTypeAndLength & 0xf0) >> 4;
             if (ipVersion != 4) {
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_NOT_IPV4);
                 throw new ParseException("Invalid IP version %d", ipVersion);
             }
 
@@ -808,6 +814,7 @@
             ipDst = readIpAddress(packet);
 
             if (ipProto != IP_TYPE_UDP) {
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_NOT_UDP);
                 throw new ParseException("Protocol not UDP: %d", ipProto);
             }
 
@@ -834,12 +841,14 @@
                 // socket to drop packets that don't have the right source ports. However, it's
                 // possible that a packet arrives between when the socket is bound and when the
                 // filter is set. http://b/26696823 .
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.L4_WRONG_PORT);
                 throw new ParseException("Unexpected UDP ports %d->%d", udpSrcPort, udpDstPort);
             }
         }
 
         // We need to check the length even for ENCAP_L3 because the IPv4 header is variable-length.
         if (pktType > ENCAP_BOOTP || packet.remaining() < MIN_PACKET_LENGTH_BOOTP) {
+            DhcpErrorEvent.logEvent(DhcpErrorEvent.BOOTP_TOO_SHORT);
             throw new ParseException("Invalid type or BOOTP packet too short, %d < %d",
                         packet.remaining(), MIN_PACKET_LENGTH_BOOTP);
         }
@@ -864,6 +873,7 @@
             packet.get(ipv4addr);
             relayIp = (Inet4Address) Inet4Address.getByAddress(ipv4addr);
         } catch (UnknownHostException ex) {
+            DhcpErrorEvent.logEvent(DhcpErrorEvent.L3_INVALID_IP);
             throw new ParseException("Invalid IPv4 address: %s", Arrays.toString(ipv4addr));
         }
 
@@ -888,6 +898,7 @@
         int dhcpMagicCookie = packet.getInt();
 
         if (dhcpMagicCookie != DHCP_MAGIC_COOKIE) {
+            DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_BAD_MAGIC_COOKIE);
             throw new ParseException("Bad magic cookie 0x%08x, should be 0x%08x", dhcpMagicCookie,
                     DHCP_MAGIC_COOKIE);
         }
@@ -896,9 +907,8 @@
         boolean notFinishedOptions = true;
 
         while ((packet.position() < packet.limit()) && notFinishedOptions) {
+            final byte optionType = packet.get(); // cannot underflow because position < limit
             try {
-                byte optionType = packet.get();
-
                 if (optionType == DHCP_OPTION_END) {
                     notFinishedOptions = false;
                 } else if (optionType == DHCP_OPTION_PAD) {
@@ -999,11 +1009,14 @@
                     }
 
                     if (expectedLen != optionLen) {
+                        DhcpErrorEvent.logEvent(
+                                DhcpErrorEvent.DHCP_INVALID_OPTION_LENGTH, optionType);
                         throw new ParseException("Invalid length %d for option %d, expected %d",
                                 optionLen, optionType, expectedLen);
                     }
                 }
             } catch (BufferUnderflowException e) {
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.BUFFER_UNDERFLOW, optionType);
                 throw new ParseException("BufferUnderflowException");
             }
         }
@@ -1012,6 +1025,7 @@
 
         switch(dhcpType) {
             case (byte) 0xFF:
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_NO_MSG_TYPE);
                 throw new ParseException("No DHCP message type option");
             case DHCP_MESSAGE_TYPE_DISCOVER:
                 newPacket = new DhcpDiscoverPacket(
@@ -1045,6 +1059,7 @@
                     clientMac);
                 break;
             default:
+                DhcpErrorEvent.logEvent(DhcpErrorEvent.DHCP_UNKNOWN_MSG_TYPE);
                 throw new ParseException("Unimplemented DHCP type %d", dhcpType);
         }
 
diff --git a/services/net/java/android/net/ip/IpManager.java b/services/net/java/android/net/ip/IpManager.java
index b6ad25b..59ebf1b 100644
--- a/services/net/java/android/net/ip/IpManager.java
+++ b/services/net/java/android/net/ip/IpManager.java
@@ -30,10 +30,12 @@
 import android.net.RouteInfo;
 import android.net.StaticIpConfiguration;
 import android.net.dhcp.DhcpClient;
+import android.net.metrics.IpManagerEvent;
 import android.os.INetworkManagementService;
 import android.os.Message;
 import android.os.RemoteException;
 import android.os.ServiceManager;
+import android.os.SystemClock;
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.SparseArray;
@@ -52,6 +54,10 @@
 import java.net.SocketException;
 import java.util.Objects;
 
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_PROVISIONING_OK;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_PROVISIONING_FAIL;
+import static android.net.metrics.IpConnectivityEvent.IPCE_IPMGR_COMPLETE_LIFECYCLE;
+
 
 /**
  * IpManager
@@ -264,6 +270,7 @@
     private ProxyInfo mHttpProxy;
     private ApfFilter mApfFilter;
     private boolean mMulticastFiltering;
+    private long mStartTimeMillis;
 
     /**
      * Member variables accessed both from within the StateMachine thread
@@ -479,6 +486,12 @@
         }
     }
 
+    private void recordMetric(final int type) {
+        if (mStartTimeMillis <= 0) { Log.wtf(mTag, "Start time undefined!"); }
+        IpManagerEvent.logEvent(type, mInterfaceName,
+                SystemClock.elapsedRealtime() - mStartTimeMillis);
+    }
+
     // For now: use WifiStateMachine's historical notion of provisioned.
     private static boolean isProvisioned(LinkProperties lp) {
         // For historical reasons, we should connect even if all we have is
@@ -536,6 +549,16 @@
             delta = ProvisioningChange.LOST_PROVISIONING;
         }
 
+        // Additionally:
+        //
+        // If the previous link properties had a global IPv6 address and an
+        // IPv6 default route then also consider the loss of that default route
+        // to be a loss of provisioning. See b/27962810.
+        if (oldLp.hasGlobalIPv6Address() && oldLp.hasIPv6DefaultRoute() &&
+                !newLp.hasIPv6DefaultRoute()) {
+            delta = ProvisioningChange.LOST_PROVISIONING;
+        }
+
         return delta;
     }
 
@@ -544,11 +567,13 @@
         switch (delta) {
             case GAINED_PROVISIONING:
                 if (VDBG) { Log.d(mTag, "onProvisioningSuccess()"); }
+                recordMetric(IPCE_IPMGR_PROVISIONING_OK);
                 mCallback.onProvisioningSuccess(newLp);
                 break;
 
             case LOST_PROVISIONING:
                 if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+                recordMetric(IPCE_IPMGR_PROVISIONING_FAIL);
                 mCallback.onProvisioningFailure(newLp);
                 break;
 
@@ -724,6 +749,10 @@
             }
 
             resetLinkProperties();
+            if (mStartTimeMillis > 0) {
+                recordMetric(IPCE_IPMGR_COMPLETE_LIFECYCLE);
+                mStartTimeMillis = 0;
+            }
         }
 
         @Override
@@ -794,11 +823,16 @@
     class StartedState extends State {
         @Override
         public void enter() {
+            mStartTimeMillis = SystemClock.elapsedRealtime();
+
             mApfFilter = ApfFilter.maybeCreate(mConfiguration.mApfCapabilities, mNetworkInterface,
                     mCallback, mMulticastFiltering);
             // TODO: investigate the effects of any multicast filtering racing/interfering with the
             // rest of this IP configuration startup.
-            if (mApfFilter == null) mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+            if (mApfFilter == null) {
+                mCallback.setFallbackMulticastFilter(mMulticastFiltering);
+            }
+
             // Set privacy extensions.
             try {
                 mNwService.setInterfaceIpv6PrivacyExtensions(mInterfaceName, true);
@@ -829,6 +863,7 @@
                     handleIPv4Success(new DhcpResults(mConfiguration.mStaticIpConfig));
                 } else {
                     if (VDBG) { Log.d(mTag, "onProvisioningFailure()"); }
+                    recordMetric(IPCE_IPMGR_PROVISIONING_FAIL);
                     mCallback.onProvisioningFailure(getLinkProperties());
                     transitionTo(mStoppingState);
                 }
diff --git a/services/net/java/android/net/ip/IpReachabilityMonitor.java b/services/net/java/android/net/ip/IpReachabilityMonitor.java
index af3175a..c8dbe02 100644
--- a/services/net/java/android/net/ip/IpReachabilityMonitor.java
+++ b/services/net/java/android/net/ip/IpReachabilityMonitor.java
@@ -26,6 +26,7 @@
 import android.net.RouteInfo;
 import android.net.metrics.IpReachabilityMonitorMessageEvent;
 import android.net.metrics.IpReachabilityMonitorProbeEvent;
+import android.net.metrics.IpReachabilityMonitorLostEvent;
 import android.net.netlink.NetlinkConstants;
 import android.net.netlink.NetlinkErrorMessage;
 import android.net.netlink.NetlinkMessage;
@@ -353,6 +354,7 @@
         }
 
         if (delta == ProvisioningChange.LOST_PROVISIONING) {
+            IpReachabilityMonitorLostEvent.logEvent(mInterfaceName);
             final String logMsg = "FAILURE: LOST_PROVISIONING, " + msg;
             Log.w(TAG, logMsg);
             if (mCallback != null) {
@@ -521,7 +523,7 @@
 
             final short msgType = neighMsg.getHeader().nlmsg_type;
             final short nudState = ndMsg.ndm_state;
-            IpReachabilityMonitorMessageEvent.logEvent(maybeGetInterfaceName(mInterfaceIndex),
+            IpReachabilityMonitorMessageEvent.logEvent(mInterfaceName,
                     destination.getHostAddress(), msgType, nudState);
             final String eventMsg = "NeighborEvent{"
                     + "elapsedMs=" + whenMs + ", "
@@ -553,11 +555,4 @@
             }
         }
     }
-
-    private String maybeGetInterfaceName(int index) {
-        if (index == mInterfaceIndex) {
-            return mInterfaceName;
-        }
-        return "ifindex-" + index;
-    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
index 26b87c5..e33be40 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/TestSystemImpl.java
@@ -24,7 +24,7 @@
 import java.util.HashMap;
 
 public class TestSystemImpl implements SystemInterface {
-    private String mUserProvider = "";
+    private String mUserProvider = null;
     private final WebViewProviderInfo[] mPackageConfigs;
     HashMap<String, PackageInfo> mPackages = new HashMap();
     private boolean mFallbackLogicEnabled;
@@ -105,6 +105,10 @@
         mPackages.put(pi.packageName, pi);
     }
 
+    public void removePackageInfo(String packageName) {
+        mPackages.remove(packageName);
+    }
+
     @Override
     public int getFactoryPackageVersion(String packageName) {
         return 0;
diff --git a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
index c00520d..c03324a 100644
--- a/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/webkit/WebViewUpdateServiceTest.java
@@ -90,12 +90,13 @@
         }
     }
 
-    private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
+    private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
             WebViewProviderInfo[] webviewPackages) {
-        checkCertainPackageUsedAfterWebViewPreparation(expectedProviderName, webviewPackages, 1);
+        checkCertainPackageUsedAfterWebViewBootPreparation(
+                expectedProviderName, webviewPackages, 1);
     }
 
-    private void checkCertainPackageUsedAfterWebViewPreparation(String expectedProviderName,
+    private void checkCertainPackageUsedAfterWebViewBootPreparation(String expectedProviderName,
             WebViewProviderInfo[] webviewPackages, int numRelros) {
         setupWithPackages(webviewPackages, true, numRelros);
         // Add (enabled and valid) package infos for each provider
@@ -156,6 +157,19 @@
         return p;
     }
 
+    private void checkPreparationPhasesForPackage(String expectedPackage, int numPreparation) {
+        // Verify that onWebViewProviderChanged was called for the numPreparation'th time for the
+        // expected package
+        Mockito.verify(mTestSystemImpl, Mockito.times(numPreparation)).onWebViewProviderChanged(
+                Mockito.argThat(new IsPackageInfoWithName(expectedPackage)));
+
+        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
+
+        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
+        assertEquals(expectedPackage, response.packageInfo.packageName);
+    }
+
 
     // ****************
     // Tests
@@ -164,7 +178,7 @@
 
     public void testWithSinglePackage() {
         String testPackageName = "test.package.name";
-        checkCertainPackageUsedAfterWebViewPreparation(testPackageName,
+        checkCertainPackageUsedAfterWebViewBootPreparation(testPackageName,
                 new WebViewProviderInfo[] {
                     new WebViewProviderInfo(testPackageName, "",
                             true /*default available*/, false /* fallback */, null)});
@@ -176,12 +190,12 @@
         WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
             new WebViewProviderInfo(nonDefaultPackage, "", false, false, null),
             new WebViewProviderInfo(defaultPackage, "", true, false, null)};
-        checkCertainPackageUsedAfterWebViewPreparation(defaultPackage, packages);
+        checkCertainPackageUsedAfterWebViewBootPreparation(defaultPackage, packages);
     }
 
     public void testSeveralRelros() {
         String singlePackage = "singlePackage";
-        checkCertainPackageUsedAfterWebViewPreparation(
+        checkCertainPackageUsedAfterWebViewBootPreparation(
                 singlePackage,
                 new WebViewProviderInfo[] {
                     new WebViewProviderInfo(singlePackage, "", true /*def av*/, false, null)},
@@ -215,14 +229,8 @@
 
         mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
 
-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
-                Mockito.argThat(new IsPackageInfoWithName(validPackage)));
 
-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
-        assertEquals(validPackage, response.packageInfo.packageName);
+        checkPreparationPhasesForPackage(validPackage, 1 /* first preparation for this package */);
 
         WebViewProviderInfo[] validPackages = mWebViewUpdateServiceImpl.getValidWebViewPackages();
         assertEquals(1, validPackages.length);
@@ -261,14 +269,27 @@
     }
 
     public void testFailListingInvalidWebviewPackage() {
-        WebViewProviderInfo wpi = new WebViewProviderInfo("", "", true, true, null);
+        WebViewProviderInfo wpi = new WebViewProviderInfo("package", "", true, true, null);
         WebViewProviderInfo[] packages = new WebViewProviderInfo[] {wpi};
         setupWithPackages(packages);
-        mTestSystemImpl.setPackageInfo(createPackageInfo(wpi.packageName, true, false));
+        mTestSystemImpl.setPackageInfo(
+                createPackageInfo(wpi.packageName, true /* enabled */, false /* valid */));
 
         mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+        Mockito.verify(mTestSystemImpl, Mockito.never()).onWebViewProviderChanged(
+                Matchers.anyObject());
+
         WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
         assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+
+        // Verify that we can recover from failing to list webview packages.
+        mTestSystemImpl.setPackageInfo(
+                createPackageInfo(wpi.packageName, true /* enabled */, true /* valid */));
+        mWebViewUpdateServiceImpl.packageStateChanged(wpi.packageName,
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+
+        checkPreparationPhasesForPackage(wpi.packageName, 1);
     }
 
     // Test that switching provider using changeProviderAndSetting works.
@@ -292,18 +313,10 @@
 
     private void checkSwitchingProvider(WebViewProviderInfo[] packages, String initialPackage,
             String finalPackage) {
-        checkCertainPackageUsedAfterWebViewPreparation(initialPackage, packages);
+        checkCertainPackageUsedAfterWebViewBootPreparation(initialPackage, packages);
 
         mWebViewUpdateServiceImpl.changeProviderAndSetting(finalPackage);
-
-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
-                Mockito.argThat(new IsPackageInfoWithName(finalPackage)));
-
-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
-        WebViewProviderResponse secondResponse = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, secondResponse.status);
-        assertEquals(finalPackage, secondResponse.packageInfo.packageName);
+        checkPreparationPhasesForPackage(finalPackage, 1 /* first preparation for this package */);
 
         Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(initialPackage));
     }
@@ -455,32 +468,20 @@
         mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
         Mockito.verify(mTestSystemImpl, Mockito.never()).uninstallAndDisablePackageForAllUsers(
                 Matchers.anyObject(), Matchers.anyObject());
-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
-                Mockito.argThat(new IsPackageInfoWithName(fallbackPackage)));
 
-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
-        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
-        assertEquals(fallbackPackage, response.packageInfo.packageName);
+        checkPreparationPhasesForPackage(fallbackPackage,
+                1 /* first preparation for this package*/);
 
         // Install primary package
         mTestSystemImpl.setPackageInfo(
                 createPackageInfo(primaryPackage, true /* enabled */ , true /* valid */));
         mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
-                WebViewUpdateService.PACKAGE_ADDED);
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED);
 
-        // Verify fallback disabled and primary package used as provider
+        // Verify fallback disabled, primary package used as provider, and fallback package killed
         Mockito.verify(mTestSystemImpl).uninstallAndDisablePackageForAllUsers(
                 Matchers.anyObject(), Mockito.eq(fallbackPackage));
-        Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
-                Mockito.argThat(new IsPackageInfoWithName(primaryPackage)));
-
-        // Finish the webview preparation and ensure primary package used and fallback killed
-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-        response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
-        assertEquals(primaryPackage, response.packageInfo.packageName);
+        checkPreparationPhasesForPackage(primaryPackage, 1 /* first preparation for this package*/);
         Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(fallbackPackage));
     }
 
@@ -502,16 +503,22 @@
                 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
                 Matchers.anyInt());
 
+        checkPreparationPhasesForPackage(primaryPackage, 1);
+
+        // Disable primary package and ensure fallback becomes enabled and used
         mTestSystemImpl.setPackageInfo(
                 createPackageInfo(primaryPackage, false /* enabled */, true /* valid */));
         mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
                 WebViewUpdateService.PACKAGE_CHANGED);
 
-        // Verify fallback becomes enabled when primary package becomes disabled
         Mockito.verify(mTestSystemImpl).enablePackageForUser(
                 Mockito.eq(fallbackPackage), Mockito.eq(true) /* enable */,
                 Matchers.anyInt());
 
+        checkPreparationPhasesForPackage(fallbackPackage, 1);
+
+
+        // Again enable primary package and verify primary is used and fallback becomes disabled
         mTestSystemImpl.setPackageInfo(
                 createPackageInfo(primaryPackage, true /* enabled */, true /* valid */));
         mWebViewUpdateServiceImpl.packageStateChanged(primaryPackage,
@@ -521,6 +528,8 @@
         Mockito.verify(mTestSystemImpl, Mockito.times(2)).enablePackageForUser(
                 Mockito.eq(fallbackPackage), Mockito.eq(false) /* enable */,
                 Matchers.anyInt());
+
+        checkPreparationPhasesForPackage(primaryPackage, 2);
     }
 
     public void testAddUserWhenFallbackLogicEnabled() {
@@ -577,6 +586,9 @@
         Mockito.verify(mTestSystemImpl).onWebViewProviderChanged(
                 Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
 
+        // Change provider during relro creation to enter a state where we are
+        // waiting for relro creation to complete just to re-run relro creation.
+        // (so that in next notifyRelroCreationCompleted() call we have to list webview packages)
         mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
 
         // Make packages invalid to cause exception to be thrown
@@ -596,18 +608,213 @@
                     true /* valid */));
 
         mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
-                WebViewUpdateService.PACKAGE_ADDED);
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED);
 
-        // Second time we call onWebViewProviderChanged for firstPackage
-        Mockito.verify(mTestSystemImpl, Mockito.times(2)).onWebViewProviderChanged(
-                Mockito.argThat(new IsPackageInfoWithName(firstPackage)));
-
-        mWebViewUpdateServiceImpl.notifyRelroCreationCompleted();
-
-        response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
-        assertEquals(WebViewFactory.LIBLOAD_SUCCESS, response.status);
-        assertEquals(firstPackage, response.packageInfo.packageName);
+        // Ensure we use firstPackage
+        checkPreparationPhasesForPackage(firstPackage, 2 /* second preparation for this package */);
     }
 
-    // TODO (gsennton) add more tests for ensuring killPackageDependents is called / not called
+    /**
+     * Verify that even if a user-chosen package is removed temporarily we start using it again when
+     * it is added back.
+     */
+    public void testTempRemovePackageDoesntSwitchProviderPermanently() {
+        String firstPackage = "first";
+        String secondPackage = "second";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(firstPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(secondPackage, "", true /* default available */,
+                    false /* fallback */, null)};
+        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+        // Explicitly use the second package
+        mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+        checkPreparationPhasesForPackage(secondPackage, 1 /* first time for this package */);
+
+        // Remove second package (invalidate it) and verify that first package is used
+        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+                    false /* valid */));
+        mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+                WebViewUpdateService.PACKAGE_ADDED);
+        checkPreparationPhasesForPackage(firstPackage, 2 /* second time for this package */);
+
+        // Now make the second package valid again and verify that it is used again
+        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+                    true /* valid */));
+        mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+                WebViewUpdateService.PACKAGE_ADDED);
+        checkPreparationPhasesForPackage(secondPackage, 2 /* second time for this package */);
+    }
+
+    /**
+     * Ensure that we update the user-chosen setting across boots if the chosen package is no
+     * longer installed and valid.
+     */
+    public void testProviderSettingChangedDuringBootIfProviderNotAvailable() {
+        String chosenPackage = "chosenPackage";
+        String nonChosenPackage = "non-chosenPackage";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(chosenPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(nonChosenPackage, "", true /* default available */,
+                    false /* fallback */, null)};
+
+        setupWithPackages(packages);
+        // Only 'install' nonChosenPackage
+        mTestSystemImpl.setPackageInfo(
+                createPackageInfo(nonChosenPackage, true /* enabled */, true /* valid */));
+
+        // Set user-chosen package
+        mTestSystemImpl.updateUserSetting(null, chosenPackage);
+
+        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+
+        // Verify that we switch the setting to point to the current package
+        Mockito.verify(mTestSystemImpl).updateUserSetting(
+                Mockito.anyObject(), Mockito.eq(nonChosenPackage));
+        assertEquals(nonChosenPackage, mTestSystemImpl.getUserChosenWebViewProvider(null));
+
+        checkPreparationPhasesForPackage(nonChosenPackage, 1);
+    }
+
+    public void testRecoverFailedListingWebViewPackagesSettingsChange() {
+        checkRecoverAfterFailListingWebviewPackages(true);
+    }
+
+    public void testRecoverFailedListingWebViewPackagesAddedPackage() {
+        checkRecoverAfterFailListingWebviewPackages(false);
+    }
+
+    /**
+     * Test that we can recover correctly from failing to list WebView packages.
+     * settingsChange: whether to fail during changeProviderAndSetting or packageStateChanged
+     */
+    public void checkRecoverAfterFailListingWebviewPackages(boolean settingsChange) {
+        String firstPackage = "first";
+        String secondPackage = "second";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(firstPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(secondPackage, "", true /* default available */,
+                    false /* fallback */, null)};
+        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+        // Make both packages invalid so that we fail listing WebView packages
+        mTestSystemImpl.setPackageInfo(createPackageInfo(firstPackage, true /* enabled */,
+                    false /* valid */));
+        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+                    false /* valid */));
+
+        // Change package to hit the webview packages listing problem.
+        if (settingsChange) {
+            mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+        } else {
+            mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+                    WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+        }
+
+        WebViewProviderResponse response = mWebViewUpdateServiceImpl.waitForAndGetProvider();
+        assertEquals(WebViewFactory.LIBLOAD_FAILED_LISTING_WEBVIEW_PACKAGES, response.status);
+
+        // Make second package valid and verify that we can load it again
+        mTestSystemImpl.setPackageInfo(createPackageInfo(secondPackage, true /* enabled */,
+                    true /* valid */));
+
+        mWebViewUpdateServiceImpl.packageStateChanged(secondPackage,
+                WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+
+
+        checkPreparationPhasesForPackage(secondPackage, 1);
+    }
+
+    public void testDontKillIfPackageReplaced() {
+        checkDontKillIfPackageRemoved(true);
+    }
+
+    public void testDontKillIfPackageRemoved() {
+        checkDontKillIfPackageRemoved(false);
+    }
+
+    public void checkDontKillIfPackageRemoved(boolean replaced) {
+        String firstPackage = "first";
+        String secondPackage = "second";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(firstPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(secondPackage, "", true /* default available */,
+                    false /* fallback */, null)};
+        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+        // Replace or remove the current webview package
+        if (replaced) {
+            mTestSystemImpl.setPackageInfo(
+                    createPackageInfo(firstPackage, true /* enabled */, false /* valid */));
+            mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
+                    WebViewUpdateService.PACKAGE_ADDED_REPLACED);
+        } else {
+            mTestSystemImpl.removePackageInfo(firstPackage);
+            mWebViewUpdateServiceImpl.packageStateChanged(firstPackage,
+                    WebViewUpdateService.PACKAGE_REMOVED);
+        }
+
+        checkPreparationPhasesForPackage(secondPackage, 1);
+
+        Mockito.verify(mTestSystemImpl, Mockito.never()).killPackageDependents(
+                Mockito.anyObject());
+    }
+
+    public void testKillIfSettingChanged() {
+        String firstPackage = "first";
+        String secondPackage = "second";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(firstPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(secondPackage, "", true /* default available */,
+                    false /* fallback */, null)};
+        checkCertainPackageUsedAfterWebViewBootPreparation(firstPackage, packages);
+
+        mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage);
+
+        checkPreparationPhasesForPackage(secondPackage, 1);
+
+        Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(firstPackage));
+    }
+
+    /**
+     * Test that we kill apps using an old provider when we change the provider setting, even if the
+     * new provider is not the one we intended to change to.
+     */
+    public void testKillIfChangeProviderIncorrectly() {
+        String firstPackage = "first";
+        String secondPackage = "second";
+        String thirdPackage = "third";
+        WebViewProviderInfo[] packages = new WebViewProviderInfo[] {
+            new WebViewProviderInfo(firstPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(secondPackage, "", true /* default available */,
+                    false /* fallback */, null),
+            new WebViewProviderInfo(thirdPackage, "", true /* default available */,
+                    false /* fallback */, null)};
+        setupWithPackages(packages);
+        setEnabledAndValidPackageInfos(packages);
+
+        // Start with the setting pointing to the third package
+        mTestSystemImpl.updateUserSetting(null, thirdPackage);
+
+        mWebViewUpdateServiceImpl.prepareWebViewInSystemServer();
+        checkPreparationPhasesForPackage(thirdPackage, 1);
+
+        mTestSystemImpl.setPackageInfo(
+                createPackageInfo(secondPackage, true /* enabled */, false /* valid */));
+
+        // Try to switch to the invalid second package, this should result in switching to the first
+        // package, since that is more preferred than the third one.
+        assertEquals(firstPackage,
+                mWebViewUpdateServiceImpl.changeProviderAndSetting(secondPackage));
+
+        checkPreparationPhasesForPackage(firstPackage, 1);
+
+        Mockito.verify(mTestSystemImpl).killPackageDependents(Mockito.eq(thirdPackage));
+    }
 }
diff --git a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
index f13e019..53377f9 100644
--- a/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
+++ b/services/voiceinteraction/java/com/android/server/soundtrigger/SoundTriggerHelper.java
@@ -84,22 +84,15 @@
     private final PhoneStateListener mPhoneStateListener;
     private final PowerManager mPowerManager;
 
-    // The SoundTriggerManager layer handles multiple generic recognition models. We store the
-    // ModelData here in a hashmap.
-    private final HashMap<UUID, ModelData> mGenericModelDataMap;
+    // The SoundTriggerManager layer handles multiple recognition models of type generic and
+    // keyphrase. We store the ModelData here in a hashmap.
+    private final HashMap<UUID, ModelData> mModelDataMap;
 
-    // This ModelData instance ensures that the keyphrase sound model is a singleton and
-    // all other sound models are of type Generic. Any keyphrase sound model will be stored here
-    // and any previously running instances will be replaced. This restriction was earlier
-    // implemented by three instance variables which stored data about the keyphrase
-    // model. That data now gets encapsulated in this ModelData instance.
-    private ModelData mKeyphraseModelData;
-
-    // The keyphrase ID for keyphrase sound models. We store this specially here since ModelData
-    // does not support this.
-    // TODO: The role of the keyphrase ID is a bit unclear. Its just used to ensure that
-    // recognition events have the correct keyphrase ID check.
-    private int mKeyphraseId = INVALID_VALUE;
+    // An index of keyphrase sound models so that we can reach them easily. We support indexing
+    // keyphrase sound models with a keyphrase ID. Sound model with the same keyphrase ID will
+    // replace an existing model, thus there is a 1:1 mapping from keyphrase ID to a voice
+    // sound model.
+    private HashMap<Integer, UUID> mKeyphraseUuidMap;
 
     private boolean mCallActive = false;
     private boolean mIsPowerSaveMode = false;
@@ -119,7 +112,8 @@
         mContext = context;
         mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
         mPowerManager = (PowerManager) context.getSystemService(Context.POWER_SERVICE);
-        mGenericModelDataMap = new HashMap<UUID, ModelData>();
+        mModelDataMap = new HashMap<UUID, ModelData>();
+        mKeyphraseUuidMap = new HashMap<Integer, UUID>();
         mPhoneStateListener = new MyCallStateListener();
         if (status != SoundTrigger.STATUS_OK || modules.size() == 0) {
             Slog.w(TAG, "listModules status=" + status + ", # of modules=" + modules.size());
@@ -153,6 +147,10 @@
 
         synchronized (mLock) {
             ModelData modelData = getOrCreateGenericModelDataLocked(modelId);
+            if (modelData == null) {
+                Slog.w(TAG, "Irrecoverable error occurred, check UUID / sound model data.");
+                return STATUS_ERROR;
+            }
             return startRecognition(soundModel, modelData, callback, recognitionConfig,
                     INVALID_VALUE /* keyphraseId */);
         }
@@ -180,20 +178,48 @@
                         + " soundModel=" + soundModel + ", callback=" + callback.asBinder()
                         + ", recognitionConfig=" + recognitionConfig);
                 Slog.d(TAG, "moduleProperties=" + mModuleProperties);
-                if (mKeyphraseModelData != null) {
-                    Slog.d(TAG, mKeyphraseModelData.toString());
-                } else {
-                    Slog.d(TAG, "Null KeyphraseModelData.");
+                dumpModelStateLocked();
+            }
+
+            ModelData model = getKeyphraseModelDataLocked(keyphraseId);
+            if (model != null && !model.isKeyphraseModel()) {
+                Slog.e(TAG, "Generic model with same UUID exists.");
+                return STATUS_ERROR;
+            }
+
+            // Process existing model first.
+            if (model != null && model.getModelId() != soundModel.uuid) {
+                // The existing model has a different UUID, should be replaced.
+                int status = cleanUpExistingKeyphraseModel(model);
+                removeKeyphraseModelLocked(keyphraseId);
+                if (status != STATUS_OK) {
+                    return status;
                 }
+                model = null;
             }
-            if (mKeyphraseModelData == null) {
-                mKeyphraseModelData = ModelData.createKeyphraseModelData(soundModel.uuid);
+
+            // We need to create a new one: either no previous models existed for given keyphrase id
+            // or the existing model had a different UUID and was cleaned up.
+            if (model == null) {
+                model = createKeyphraseModelDataLocked(soundModel.uuid, keyphraseId);
             }
-            return startRecognition(soundModel, mKeyphraseModelData, callback, recognitionConfig,
+
+            return startRecognition(soundModel, model, callback, recognitionConfig,
                     keyphraseId);
         }
     }
 
+    private int cleanUpExistingKeyphraseModel(ModelData modelData) {
+        // Stop and clean up a previous ModelData if one exists. This usually is used when the
+        // previous model has a different UUID for the same keyphrase ID.
+        int status = tryStopAndUnloadLocked(modelData, true /* stop */, true /* unload */);
+        if (status != STATUS_OK) {
+            Slog.w(TAG, "Unable to stop or unload previous model: " +
+                    modelData.toString());
+        }
+        return status;
+    }
+
     /**
      * Starts recognition for the given sound model. A single routine for both keyphrase and
      * generic sound models.
@@ -228,17 +254,15 @@
                 initializeTelephonyAndPowerStateListeners();
             }
 
-            // If the previous model is different (for the same UUID), ensure that its unloaded
-            // and stopped before proceeding. This works for both keyphrase and generic models.
-            // Specifically for keyphrase since we have 'mKeyphraseModelData' holding a single
-            // allowed instance of such a model, this ensures that a previously loaded (or started)
-            // keyphrase model is appropriately stopped. This ensures no regression with the
-            // previous version of this code as given in the startKeyphrase() routine.
-            //
-            // For generic sound models, all this means is that if we are given a different sound
-            // model with the same UUID, then we will "replace" it.
+            // If the existing SoundModel is different (for the same UUID for Generic and same
+            // keyphrase ID for voice), ensure that it is unloaded and stopped before proceeding.
+            // This works for both keyphrase and generic models. This logic also ensures that a
+            // previously loaded (or started) model is appropriately stopped. Since this is a
+            // generalization of the previous logic with a single keyphrase model, we should have
+            // no regression with the previous version of this code as was given in the
+            // startKeyphrase() routine.
             if (modelData.getSoundModel() != null) {
-                boolean stopModel = false; // Stop the model after checking that its started.
+                boolean stopModel = false; // Stop the model after checking that it is started.
                 boolean unloadModel = false;
                 if (modelData.getSoundModel().equals(soundModel) && modelData.isModelStarted()) {
                     // The model has not changed, but the previous model is "started".
@@ -273,7 +297,7 @@
                 modelData.clearCallback();
             }
 
-            // Load the model if its not loaded.
+            // Load the model if it is not loaded.
             if (!modelData.isModelLoaded()) {
                 // Load the model
                 int[] handle = new int[] { INVALID_VALUE };
@@ -291,9 +315,6 @@
                 Slog.d(TAG, "Sound model loaded with handle:" + handle[0]);
             }
             modelData.setCallback(callback);
-            if (modelData.isKeyphraseModel()) {
-                mKeyphraseId = keyphraseId;
-            }
             modelData.setRequested(true);
             modelData.setRecognitionConfig(recognitionConfig);
             modelData.setSoundModel(soundModel);
@@ -322,8 +343,8 @@
                 return STATUS_ERROR;
             }
 
-            ModelData modelData = mGenericModelDataMap.get(modelId);
-            if (modelData == null) {
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null || !modelData.isGenericModel()) {
                 Slog.w(TAG, "Attempting stopRecognition on invalid model with id:" + modelId);
                 return STATUS_ERROR;
             }
@@ -355,21 +376,23 @@
                 return STATUS_ERROR;
             }
 
+            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
+            if (modelData == null || !modelData.isKeyphraseModel()) {
+                Slog.e(TAG, "No model exists for given keyphrase Id.");
+                return STATUS_ERROR;
+            }
+
             if (DBG) {
                 Slog.d(TAG, "stopRecognition for keyphraseId=" + keyphraseId + ", callback =" +
                         callback.asBinder());
-                Slog.d(TAG, "current callback=" + (mKeyphraseModelData == null ? "null" :
-                            mKeyphraseModelData.getCallback().asBinder()));
+                Slog.d(TAG, "current callback=" + (modelData == null ? "null" :
+                            modelData.getCallback().asBinder()));
             }
-            int status = stopRecognition(mKeyphraseModelData, callback);
+            int status = stopRecognition(modelData, callback);
             if (status != SoundTrigger.STATUS_OK) {
                 return status;
             }
 
-            // We leave the sound model loaded but not started, this helps us when we start
-            // back.
-            // Also clear the internal state once the recognition has been stopped.
-            internalClearKeyphraseStateLocked();
             return status;
         }
     }
@@ -424,9 +447,6 @@
                 internalClearGlobalStateLocked();
             }
 
-            if (modelData.isKeyphraseModel()) {
-                mKeyphraseId = INVALID_VALUE;
-            }
             return status;
         }
     }
@@ -475,25 +495,18 @@
                 return;
             }
 
-            // Stop Keyphrase recognition if one exists.
-            if (mKeyphraseModelData != null && mKeyphraseModelData.getHandle() != INVALID_VALUE) {
-                mKeyphraseModelData.setRequested(false);
-                int status = updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
-                        false /* don't notify for synchronous calls */);
-                internalClearKeyphraseStateLocked();
-            }
-
-            // Stop all generic recognition models.
-            for (ModelData model : mGenericModelDataMap.values()) {
+            // Stop all recognition models.
+            for (ModelData model : mModelDataMap.values()) {
                 if (model.isModelStarted()) {
+                    model.setRequested(false);
                     int status = stopRecognitionLocked(model,
                             false /* do not notify for synchronous calls */);
                     if (status != STATUS_OK) {
-                        // What else can we do if there is an error here.
-                        Slog.w(TAG, "Error stopping generic model: " + model.getHandle());
+                        Slog.w(TAG, "Error stopping keyphrase model: " + model.getHandle());
                     }
                     model.clearState();
                     model.clearCallback();
+                    model.setRecognitionConfig(null);
                 }
             }
             internalClearGlobalStateLocked();
@@ -507,24 +520,27 @@
     int unloadKeyphraseSoundModel(int keyphraseId) {
         synchronized (mLock) {
             MetricsLogger.count(mContext, "sth_unload_keyphrase_sound_model", 1);
-            if (mModule == null || mKeyphraseModelData == null ||
-                    mKeyphraseModelData.getHandle() == INVALID_VALUE) {
+            ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
+            if (mModule == null || modelData == null || modelData.getHandle() == INVALID_VALUE ||
+                    !modelData.isKeyphraseModel()) {
                 return STATUS_ERROR;
             }
 
             // Stop recognition if it's the current one.
-            mKeyphraseModelData.setRequested(false);
-            int status = updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
+            modelData.setRequested(false);
+            int status = updateRecognitionLocked(modelData, isRecognitionAllowed(),
                     false /* don't notify */);
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "Stop recognition failed for keyphrase ID:" + status);
             }
 
-            status = mModule.unloadSoundModel(mKeyphraseModelData.getHandle());
+            status = mModule.unloadSoundModel(modelData.getHandle());
             if (status != SoundTrigger.STATUS_OK) {
                 Slog.w(TAG, "unloadKeyphraseSoundModel call failed with " + status);
             }
-            mKeyphraseModelData.clearState();
+
+            // Remove it from existence.
+            removeKeyphraseModelLocked(keyphraseId);
             return status;
         }
     }
@@ -535,8 +551,8 @@
             if (modelId == null || mModule == null) {
                 return STATUS_ERROR;
             }
-            ModelData modelData = mGenericModelDataMap.get(modelId);
-            if (modelData == null) {
+            ModelData modelData = mModelDataMap.get(modelId);
+            if (modelData == null || !modelData.isGenericModel()) {
                 Slog.w(TAG, "Unload error: Attempting unload invalid generic model with id:" +
                         modelId);
                 return STATUS_ERROR;
@@ -559,8 +575,10 @@
                 Slog.w(TAG, "unloadGenericSoundModel() call failed with " + status);
                 Slog.w(TAG, "unloadGenericSoundModel() force-marking model as unloaded.");
             }
-            mGenericModelDataMap.remove(modelId);
-            if (DBG) dumpGenericModelStateLocked();
+
+            // Remove it from existence.
+            mModelDataMap.remove(modelId);
+            if (DBG) dumpModelStateLocked();
             return status;
         }
     }
@@ -612,7 +630,7 @@
             return;
         }
         ModelData model = getModelDataForLocked(event.soundModelHandle);
-        if (model == null) {
+        if (model == null || !model.isGenericModel()) {
             Slog.w(TAG, "Generic recognition event: Model does not exist for handle: " +
                     event.soundModelHandle);
             return;
@@ -723,67 +741,64 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onError", e);
         } finally {
-            internalClearKeyphraseStateLocked();
-            internalClearGenericModelStateLocked();
+            internalClearModelStateLocked();
             internalClearGlobalStateLocked();
         }
     }
 
+    private int getKeyphraseIdFromEvent(KeyphraseRecognitionEvent event) {
+        if (event == null) {
+            Slog.w(TAG, "Null RecognitionEvent received.");
+            return INVALID_VALUE;
+        }
+        KeyphraseRecognitionExtra[] keyphraseExtras =
+                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
+        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
+            Slog.w(TAG, "Invalid keyphrase recognition event!");
+            return INVALID_VALUE;
+        }
+        // TODO: Handle more than one keyphrase extras.
+        return keyphraseExtras[0].id;
+    }
+
     private void onKeyphraseRecognitionSuccessLocked(KeyphraseRecognitionEvent event) {
         Slog.i(TAG, "Recognition success");
         MetricsLogger.count(mContext, "sth_keyphrase_recognition_event", 1);
+        int keyphraseId = getKeyphraseIdFromEvent(event);
+        ModelData modelData = getKeyphraseModelDataLocked(keyphraseId);
 
-        if (mKeyphraseModelData == null) {
-            Slog.e(TAG, "Received onRecognition event for null keyphrase model data.");
+        if (modelData == null || !modelData.isKeyphraseModel()) {
+            Slog.e(TAG, "Keyphase model data does not exist for ID:" + keyphraseId);
             return;
         }
 
-        if (mKeyphraseModelData.getCallback() == null) {
-            Slog.w(TAG, "Received onRecognition event without any listener for it.");
-            return;
-        }
-
-        KeyphraseRecognitionExtra[] keyphraseExtras =
-                ((KeyphraseRecognitionEvent) event).keyphraseExtras;
-        if (keyphraseExtras == null || keyphraseExtras.length == 0) {
-            Slog.w(TAG, "Invalid keyphrase recognition event!");
-            return;
-        }
-        // TODO: Handle more than one keyphrase extras.
-        if (mKeyphraseId != keyphraseExtras[0].id) {
-            Slog.w(TAG, "received onRecognition event for a different keyphrase");
+        if (modelData.getCallback() == null) {
+            Slog.w(TAG, "Received onRecognition event without callback for keyphrase model.");
             return;
         }
 
         try {
-            mKeyphraseModelData.getCallback().onKeyphraseDetected(
-                    (KeyphraseRecognitionEvent) event);
+            modelData.getCallback().onKeyphraseDetected((KeyphraseRecognitionEvent) event);
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onKeyphraseDetected", e);
         }
 
-        mKeyphraseModelData.setStopped();
+        modelData.setStopped();
 
-        RecognitionConfig config = mKeyphraseModelData.getRecognitionConfig();
+        RecognitionConfig config = modelData.getRecognitionConfig();
         if (config != null) {
             // Whether we should continue by starting this again.
-            mKeyphraseModelData.setRequested(config.allowMultipleTriggers);
+            modelData.setRequested(config.allowMultipleTriggers);
         }
         // TODO: Remove this block if the lower layer supports multiple triggers.
-        if (mKeyphraseModelData.getRequested()) {
-            updateRecognitionLocked(mKeyphraseModelData, isRecognitionAllowed(),
-                true /* notify */);
+        if (modelData.getRequested()) {
+            updateRecognitionLocked(modelData, isRecognitionAllowed(), true /* notify */);
         }
     }
 
     private void updateAllRecognitionsLocked(boolean notify) {
         boolean isAllowed = isRecognitionAllowed();
-        // Keyphrase model.
-        if (mKeyphraseModelData != null) {
-            updateRecognitionLocked(mKeyphraseModelData, isAllowed, notify);
-        }
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+        for (ModelData modelData : mModelDataMap.values()) {
             updateRecognitionLocked(modelData, isAllowed, notify);
         }
     }
@@ -809,11 +824,7 @@
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException in onError", e);
         } finally {
-            if (mKeyphraseModelData != null) {
-                mKeyphraseModelData.clearState();
-            }
-            internalClearKeyphraseStateLocked();
-            internalClearGenericModelStateLocked();
+            internalClearModelStateLocked();
             internalClearGlobalStateLocked();
             if (mModule != null) {
                 mModule.detach();
@@ -822,10 +833,7 @@
         }
     }
 
-    // internalClearGlobalStateLocked() gets split into two routines. Cleanup that is
-    // specific to keyphrase sound models named as internalClearKeyphraseStateLocked() and
-    // internalClearGlobalStateLocked() for global state. The global cleanup routine will be used
-    // by the cleanup happening with the generic sound models.
+    // internalClearGlobalStateLocked() cleans up the telephony and power save listeners.
     private void internalClearGlobalStateLocked() {
         // Unregister from call state changes.
         mTelephonyManager.listen(mPhoneStateListener, PhoneStateListener.LISTEN_NONE);
@@ -837,20 +845,9 @@
         }
     }
 
-    private void internalClearKeyphraseStateLocked() {
-        if (mKeyphraseModelData != null) {
-            mKeyphraseModelData.setStopped();
-            mKeyphraseModelData.setRequested(false);
-            mKeyphraseModelData.setRecognitionConfig(null);
-            mKeyphraseModelData.setCallback(null);
-        }
-
-        mKeyphraseId = INVALID_VALUE;
-    }
-
-    private void internalClearGenericModelStateLocked() {
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+    // Clears state for all models (generic and keyphrase).
+    private void internalClearModelStateLocked() {
+        for (ModelData modelData : mModelDataMap.values()) {
             modelData.clearState();
             modelData.clearCallback();
         }
@@ -884,14 +881,10 @@
         synchronized (mLock) {
             pw.print("  module properties=");
             pw.println(mModuleProperties == null ? "null" : mModuleProperties);
-            pw.print("  keyphrase ID="); pw.println(mKeyphraseId);
 
             pw.print("  call active="); pw.println(mCallActive);
             pw.print("  power save mode active="); pw.println(mIsPowerSaveMode);
             pw.print("  service disabled="); pw.println(mServiceDisabled);
-            if (mKeyphraseModelData != null) {
-                pw.println(mKeyphraseModelData.toString());
-            }
         }
     }
 
@@ -914,34 +907,60 @@
 
     // Sends an error callback to all models with a valid registered callback.
     private void sendErrorCallbacksToAll(int errorCode) throws RemoteException {
-        IRecognitionStatusCallback keyphraseListener = mKeyphraseModelData.getCallback();
-        if (keyphraseListener != null) {
-            keyphraseListener.onError(STATUS_ERROR);
-        }
-        for (UUID modelId: mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
-            IRecognitionStatusCallback keyphraseCallback = mKeyphraseModelData.getCallback();
-            if (keyphraseCallback != null) {
-                keyphraseCallback.onError(STATUS_ERROR);
+        for (ModelData modelData : mModelDataMap.values()) {
+            IRecognitionStatusCallback callback = modelData.getCallback();
+            if (callback != null) {
+                callback.onError(STATUS_ERROR);
             }
         }
     }
 
     private ModelData getOrCreateGenericModelDataLocked(UUID modelId) {
-        ModelData modelData = mGenericModelDataMap.get(modelId);
+        ModelData modelData = mModelDataMap.get(modelId);
         if (modelData == null) {
             modelData = ModelData.createGenericModelData(modelId);
-            mGenericModelDataMap.put(modelId, modelData);
+            mModelDataMap.put(modelId, modelData);
+        } else if (!modelData.isGenericModel()) {
+            Slog.e(TAG, "UUID already used for non-generic model.");
+            return null;
         }
         return modelData;
     }
 
+    private void removeKeyphraseModelLocked(int keyphraseId) {
+        UUID uuid = mKeyphraseUuidMap.get(keyphraseId);
+        if (uuid == null) {
+            return;
+        }
+        mModelDataMap.remove(uuid);
+        mKeyphraseUuidMap.remove(keyphraseId);
+    }
+
+    private ModelData getKeyphraseModelDataLocked(int keyphraseId) {
+        UUID uuid = mKeyphraseUuidMap.get(keyphraseId);
+        if (uuid == null) {
+            return null;
+        }
+        return mModelDataMap.get(uuid);
+    }
+
+    // Use this to create a new ModelData entry for a keyphrase Id. It will overwrite existing
+    // mapping if one exists.
+    private ModelData createKeyphraseModelDataLocked(UUID modelId, int keyphraseId) {
+        mKeyphraseUuidMap.remove(keyphraseId);
+        mModelDataMap.remove(modelId);
+        mKeyphraseUuidMap.put(keyphraseId, modelId);
+        ModelData modelData = ModelData.createKeyphraseModelData(modelId);
+        mModelDataMap.put(modelId, modelData);
+        return modelData;
+    }
+
     // Instead of maintaining a second hashmap of modelHandle -> ModelData, we just
     // iterate through to find the right object (since we don't expect 100s of models
     // to be stored).
     private ModelData getModelDataForLocked(int modelHandle) {
         // Fetch ModelData object corresponding to the model handle.
-        for (ModelData model : mGenericModelDataMap.values()) {
+        for (ModelData model : mModelDataMap.values()) {
             if (model.getHandle() == modelHandle) {
                 return model;
             }
@@ -1051,9 +1070,9 @@
         return status;
     }
 
-    private void dumpGenericModelStateLocked() {
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+    private void dumpModelStateLocked() {
+        for (UUID modelId : mModelDataMap.keySet()) {
+            ModelData modelData = mModelDataMap.get(modelId);
             Slog.i(TAG, "Model :" + modelData.toString());
         }
     }
@@ -1065,14 +1084,7 @@
             mRecognitionRunning = false;
             return mRecognitionRunning;
         }
-        if (mKeyphraseModelData != null && mKeyphraseModelData.getCallback() != null &&
-                mKeyphraseModelData.isModelStarted() &&
-            mKeyphraseModelData.getHandle() != INVALID_VALUE) {
-            mRecognitionRunning = true;
-            return mRecognitionRunning;
-        }
-        for (UUID modelId : mGenericModelDataMap.keySet()) {
-            ModelData modelData = mGenericModelDataMap.get(modelId);
+        for (ModelData modelData : mModelDataMap.values()) {
             if (modelData.isModelStarted()) {
                 mRecognitionRunning = true;
                 return mRecognitionRunning;
@@ -1233,6 +1245,10 @@
             return mModelType == SoundModel.TYPE_KEYPHRASE;
         }
 
+        synchronized boolean isGenericModel() {
+            return mModelType == SoundModel.TYPE_GENERIC_SOUND;
+        }
+
         synchronized String stateToString() {
             switch(mModelState) {
                 case MODEL_NOTLOADED: return "NOT_LOADED";
@@ -1259,7 +1275,17 @@
                     "ModelState: " + stateToString() + "\n" +
                     requestedToString() + "\n" +
                     callbackToString() + "\n" +
-                    uuidToString();
+                    uuidToString() + "\n" + modelTypeToString();
+        }
+
+        synchronized String modelTypeToString() {
+            String type = null;
+            switch (mModelType) {
+                case SoundModel.TYPE_GENERIC_SOUND: type = "Generic"; break;
+                case SoundModel.TYPE_UNKNOWN: type = "Unknown"; break;
+                case SoundModel.TYPE_KEYPHRASE: type = "Keyphrase"; break;
+            }
+            return "Model type: " + type + "\n";
         }
     }
 }
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 1544723..1e9db18 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -17,6 +17,7 @@
 package com.android.server.voiceinteraction;
 
 import android.app.ActivityManager;
+import android.app.ActivityManagerInternal;
 import android.app.ActivityManagerNative;
 import android.app.IActivityManager;
 import android.content.BroadcastReceiver;
@@ -42,9 +43,11 @@
 
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
+import com.android.server.LocalServices;
 
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.util.List;
 
 class VoiceInteractionManagerServiceImpl implements VoiceInteractionSessionConnection.Callback {
     final static String TAG = "VoiceInteractionServiceManager";
@@ -148,8 +151,14 @@
             mActiveSession = new VoiceInteractionSessionConnection(mLock, mSessionComponentName,
                     mUser, mContext, this, mInfo.getServiceInfo().applicationInfo.uid, mHandler);
         }
+        List<IBinder> activityTokens = null;
+        if (activityToken == null) {
+            // Let's get top activities from all visible stacks
+            activityTokens = LocalServices.getService(ActivityManagerInternal.class)
+                    .getTopVisibleActivities();
+        }
         return mActiveSession.showLocked(args, flags, mDisabledShowContext, showCallback,
-                activityToken);
+                activityToken, activityTokens);
     }
 
     public boolean hideSessionLocked() {
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
index e04f312..0922a12 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionSessionConnection.java
@@ -45,6 +45,7 @@
 import android.util.Slog;
 import android.view.IWindowManager;
 import android.view.WindowManager;
+
 import com.android.internal.app.IAssistScreenshotReceiver;
 import com.android.internal.app.IVoiceInteractionSessionShowCallback;
 import com.android.internal.app.IVoiceInteractor;
@@ -55,10 +56,15 @@
 
 import java.io.PrintWriter;
 import java.util.ArrayList;
+import java.util.List;
 
 final class VoiceInteractionSessionConnection implements ServiceConnection {
+
     final static String TAG = "VoiceInteractionServiceManager";
 
+    private static final String KEY_RECEIVER_EXTRA_COUNT = "count";
+    private static final String KEY_RECEIVER_EXTRA_INDEX = "index";
+
     final IBinder mToken = new Binder();
     final Object mLock;
     final ComponentName mSessionComponentName;
@@ -82,11 +88,27 @@
     IVoiceInteractionSession mSession;
     IVoiceInteractor mInteractor;
     boolean mHaveAssistData;
-    Bundle mAssistData;
+    int mPendingAssistDataCount;
+    ArrayList<AssistDataForActivity> mAssistData = new ArrayList<>();
     boolean mHaveScreenshot;
     Bitmap mScreenshot;
     ArrayList<IVoiceInteractionSessionShowCallback> mPendingShowCallbacks = new ArrayList<>();
 
+    static class AssistDataForActivity {
+        int activityIndex;
+        int activityCount;
+        Bundle data;
+
+        public AssistDataForActivity(Bundle data) {
+            this.data = data;
+            Bundle receiverExtras = data.getBundle(VoiceInteractionSession.KEY_RECEIVER_EXTRAS);
+            if (receiverExtras != null) {
+                activityIndex = receiverExtras.getInt(KEY_RECEIVER_EXTRA_INDEX);
+                activityCount = receiverExtras.getInt(KEY_RECEIVER_EXTRA_COUNT);
+            }
+        }
+    }
+
     IVoiceInteractionSessionShowCallback mShowCallback =
             new IVoiceInteractionSessionShowCallback.Stub() {
         @Override
@@ -125,7 +147,7 @@
             synchronized (mLock) {
                 if (mShown) {
                     mHaveAssistData = true;
-                    mAssistData = resultData;
+                    mAssistData.add(new AssistDataForActivity(resultData));
                     deliverSessionDataLocked();
                 }
             }
@@ -198,7 +220,8 @@
     }
 
     public boolean showLocked(Bundle args, int flags, int disabledContext,
-            IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken) {
+            IVoiceInteractionSessionShowCallback showCallback, IBinder activityToken,
+            List<IBinder> topActivities) {
         if (mBound) {
             if (!mFullyBound) {
                 mFullyBound = mContext.bindServiceAsUser(mBindIntent, mFullConnection,
@@ -220,30 +243,41 @@
             mShowArgs = args;
             mShowFlags = flags;
             mHaveAssistData = false;
+            mPendingAssistDataCount = 0;
             boolean needDisclosure = false;
             if ((flags&VoiceInteractionSession.SHOW_WITH_ASSIST) != 0) {
                 if (mAppOps.noteOpNoThrow(AppOpsManager.OP_ASSIST_STRUCTURE, mCallingUid,
                         mSessionComponentName.getPackageName()) == AppOpsManager.MODE_ALLOWED
                         && structureEnabled) {
-                    try {
-                        MetricsLogger.count(mContext, "assist_with_context", 1);
-                        if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
-                                mAssistReceiver, activityToken)) {
-                            needDisclosure = true;
-                        } else {
-                            // Wasn't allowed...  given that, let's not do the screenshot either.
-                            mHaveAssistData = true;
-                            mAssistData = null;
-                            screenshotEnabled = false;
+                    mAssistData.clear();
+                    final int count = activityToken != null ? 1 : topActivities.size();
+                    for (int i = 0; i < count; i++) {
+                        IBinder topActivity = count == 1 ? activityToken : topActivities.get(i);
+                        try {
+                            MetricsLogger.count(mContext, "assist_with_context", 1);
+                            Bundle receiverExtras = new Bundle();
+                            receiverExtras.putInt(KEY_RECEIVER_EXTRA_INDEX, i);
+                            receiverExtras.putInt(KEY_RECEIVER_EXTRA_COUNT, count);
+                            if (mAm.requestAssistContextExtras(ActivityManager.ASSIST_CONTEXT_FULL,
+                                    mAssistReceiver, receiverExtras, topActivity, i == 0)) {
+                                needDisclosure = true;
+                                mPendingAssistDataCount++;
+                            } else if (i == 0) {
+                                // Wasn't allowed... given that, let's not do the screenshot either.
+                                mHaveAssistData = true;
+                                mAssistData.clear();
+                                screenshotEnabled = false;
+                                break;
+                            }
+                        } catch (RemoteException e) {
                         }
-                    } catch (RemoteException e) {
                     }
                 } else {
                     mHaveAssistData = true;
-                    mAssistData = null;
+                    mAssistData.clear();
                 }
             } else {
-                mAssistData = null;
+                mAssistData.clear();
             }
             mHaveScreenshot = false;
             if ((flags&VoiceInteractionSession.SHOW_WITH_SCREENSHOT) != 0) {
@@ -335,41 +369,26 @@
             return;
         }
         if (mHaveAssistData) {
-            Bundle assistData;
-            AssistStructure structure;
-            AssistContent content;
-            if (mAssistData != null) {
-                assistData = mAssistData.getBundle("data");
-                structure = mAssistData.getParcelable("structure");
-                content = mAssistData.getParcelable("content");
-                int uid = mAssistData.getInt(Intent.EXTRA_ASSIST_UID, -1);
-                if (uid >= 0 && content != null) {
-                    Intent intent = content.getIntent();
-                    if (intent != null) {
-                        ClipData data = intent.getClipData();
-                        if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
-                            grantClipDataPermissions(data, intent.getFlags(), uid,
-                                    mCallingUid, mSessionComponentName.getPackageName());
-                        }
-                    }
-                    ClipData data = content.getClipData();
-                    if (data != null) {
-                        grantClipDataPermissions(data,
-                                Intent.FLAG_GRANT_READ_URI_PERMISSION,
-                                uid, mCallingUid, mSessionComponentName.getPackageName());
-                    }
+            AssistDataForActivity assistData;
+            while (!mAssistData.isEmpty()) {
+                if (mPendingAssistDataCount <= 0) {
+                    Slog.e(TAG, "mPendingAssistDataCount is " + mPendingAssistDataCount);
                 }
-            } else {
-                assistData = null;
-                structure = null;
-                content = null;
+                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);
+                }
             }
-            try {
-                mSession.handleAssist(assistData, structure, content);
-            } catch (RemoteException e) {
-            }
-            mAssistData = null;
-            mHaveAssistData = false;
+            if (mPendingAssistDataCount <= 0) {
+                mHaveAssistData = false;
+            } // else, more to come
         }
         if (mHaveScreenshot) {
             try {
@@ -381,6 +400,37 @@
         }
     }
 
+    private void deliverSessionDataLocked(AssistDataForActivity assistDataForActivity) {
+        Bundle assistData = assistDataForActivity.data.getBundle(
+                VoiceInteractionSession.KEY_DATA);
+        AssistStructure structure = assistDataForActivity.data.getParcelable(
+                VoiceInteractionSession.KEY_STRUCTURE);
+        AssistContent content = assistDataForActivity.data.getParcelable(
+                VoiceInteractionSession.KEY_CONTENT);
+        int uid = assistDataForActivity.data.getInt(Intent.EXTRA_ASSIST_UID, -1);
+        if (uid >= 0 && content != null) {
+            Intent intent = content.getIntent();
+            if (intent != null) {
+                ClipData data = intent.getClipData();
+                if (data != null && Intent.isAccessUriMode(intent.getFlags())) {
+                    grantClipDataPermissions(data, intent.getFlags(), uid,
+                            mCallingUid, mSessionComponentName.getPackageName());
+                }
+            }
+            ClipData data = content.getClipData();
+            if (data != null) {
+                grantClipDataPermissions(data,
+                        Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                        uid, mCallingUid, mSessionComponentName.getPackageName());
+            }
+        }
+        try {
+            mSession.handleAssist(assistData, structure, content,
+                    assistDataForActivity.activityIndex, assistDataForActivity.activityCount);
+        } catch (RemoteException e) {
+        }
+    }
+
     public boolean hideLocked() {
         if (mBound) {
             if (mShown) {
@@ -388,7 +438,7 @@
                 mShowArgs = null;
                 mShowFlags = 0;
                 mHaveAssistData = false;
-                mAssistData = null;
+                mAssistData.clear();
                 if (mSession != null) {
                     try {
                         mSession.hide();
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index c18c13c..26730de 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -548,6 +548,27 @@
     public static final String KEY_EDITABLE_WFC_MODE_BOOL = "editable_wfc_mode_bool";
 
     /**
+     * List operator-specific error codes and indices of corresponding error strings in
+     * wfcOperatorErrorAlertMessages and wfcOperatorErrorNotificationMessages.
+     *
+     * Example: "REG09|0" specifies error code "REG09" and index "0". This index will be
+     * used to find alert and notification messages in wfcOperatorErrorAlertMessages and
+     * wfcOperatorErrorNotificationMessages.
+     *
+     * @hide
+     */
+    public static final String KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY =
+            "wfc_operator_error_codes_string_array";
+
+    /**
+     * Indexes of SPN format strings in wfcSpnFormats and wfcDataSpnFormats.
+     * @hide
+     */
+    public static final String KEY_WFC_SPN_FORMAT_IDX_INT = "wfc_spn_format_idx_int";
+    /** @hide */
+    public static final String KEY_WFC_DATA_SPN_FORMAT_IDX_INT = "wfc_data_spn_format_idx_int";
+
+    /**
      * If this is true, the SIM card (through Customer Service Profile EF file) will be able to
      * prevent manual operator selection. If false, this SIM setting will be ignored and manual
      * operator selection will always be available. See CPHS4_2.WW6, CPHS B.4.7.1 for more
@@ -693,8 +714,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_BOOLEAN, false);
+        sDefaults.putBoolean(KEY_VVM_PREFETCH_BOOLEAN, 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);
@@ -731,6 +752,9 @@
         sDefaults.putBoolean(KEY_HIDE_PREFERRED_NETWORK_TYPE_BOOL, false);
         sDefaults.putBoolean(KEY_ALLOW_EMERGENCY_VIDEO_CALLS_BOOL, false);
         sDefaults.putBoolean(KEY_EDITABLE_WFC_MODE_BOOL, true);
+        sDefaults.putStringArray(KEY_WFC_OPERATOR_ERROR_CODES_STRING_ARRAY, null);
+        sDefaults.putInt(KEY_WFC_SPN_FORMAT_IDX_INT, 0);
+        sDefaults.putInt(KEY_WFC_DATA_SPN_FORMAT_IDX_INT, 0);
 
         // MMS defaults
         sDefaults.putBoolean(KEY_MMS_ALIAS_ENABLED_BOOL, false);
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 638b286..0bca628 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -3644,22 +3644,6 @@
     }
 
     /**
-     * Returns the response of SIM Authentication through RIL for the default subscription.
-     * Returns null if the Authentication hasn't been successful
-     *
-     * <p>Requires that the calling app has carrier privileges.
-     * @see #hasCarrierPrivileges
-     *
-     * @param appType ICC application type (@see com.android.internal.telephony.PhoneConstants#APPTYPE_xxx)
-     * @param data authentication challenge data
-     * @return the response of SIM Authentication, or null if not available
-     * @hide
-     */
-    public String getIccSimChallengeResponse(int appType, String data) {
-        return getIccAuthentication(getDefaultSubscription(), appType, AUTHTYPE_EAP_SIM, data);
-    }
-
-    /**
      * Get P-CSCF address from PCO after data connection is established or modified.
      * @param apnType the apnType, "ims" for IMS APN, "emergency" for EMERGENCY APN
      * @return array of P-CSCF address
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
deleted file mode 100644
index 069fcbf..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebug.aidl
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.ITelephonyDebugSubscriber;
-
-import android.os.Bundle;
-
-/**
- * Interface used to interact with the Telephony debug service.
- *
- * {@hide}
- */
-interface ITelephonyDebug {
-
-    /**
-     * Write telephony event
-     * @param timestamp returned by System.currentTimeMillis()
-     * @param phoneId for which event is written
-     * @param tag constant defined in TelephonyEventLog
-     * @param param1 optional
-     * @param param2 optional
-     * @param data optional
-     */
-    void writeEvent(long timestamp, int phoneId, int tag, int param1, int param2, in Bundle data);
-
-    void subscribe(in ITelephonyDebugSubscriber subscriber);
-    void unsubscribe(in ITelephonyDebugSubscriber subscriber);
-}
diff --git a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl b/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
deleted file mode 100644
index 64eb0f1..0000000
--- a/telephony/java/com/android/internal/telephony/ITelephonyDebugSubscriber.aidl
+++ /dev/null
@@ -1,34 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import com.android.internal.telephony.TelephonyEvent;
-
-import android.os.Bundle;
-
-/**
- * Interface used to subscribe for events from Telephony debug service.
- *
- * {@hide}
- */
-oneway interface ITelephonyDebugSubscriber {
-
-    /**
-     * Called when Telephony debug service has events.
-     */
-    void onEvents(in TelephonyEvent[] events);
-}
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl b/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
deleted file mode 100644
index 1e74b31..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-parcelable TelephonyEvent;
diff --git a/telephony/java/com/android/internal/telephony/TelephonyEvent.java b/telephony/java/com/android/internal/telephony/TelephonyEvent.java
deleted file mode 100644
index 26d466d..0000000
--- a/telephony/java/com/android/internal/telephony/TelephonyEvent.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.telephony;
-
-import android.os.Bundle;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- *  A parcelable used in ITelephonyDebugSubscriber.aidl
- */
-public class TelephonyEvent implements Parcelable {
-
-    final public long timestamp;
-    final public int phoneId;
-    final public int tag;
-    final public int param1;
-    final public int param2;
-    final public Bundle data;
-
-    public TelephonyEvent(long timestamp, int phoneId, int tag,
-            int param1, int param2, Bundle data) {
-        this.timestamp = timestamp;
-        this.phoneId = phoneId;
-        this.tag = tag;
-        this.param1 = param1;
-        this.param2 = param2;
-        this.data = data;
-    }
-
-    /** Implement the Parcelable interface */
-    public static final Parcelable.Creator<TelephonyEvent> CREATOR
-            = new Parcelable.Creator<TelephonyEvent> (){
-        public TelephonyEvent createFromParcel(Parcel source) {
-            final long timestamp = source.readLong();
-            final int phoneId = source.readInt();
-            final int tag = source.readInt();
-            final int param1 = source.readInt();
-            final int param2 = source.readInt();
-            final Bundle data = source.readBundle();
-            return new TelephonyEvent(timestamp, phoneId, tag, param1, param2, data);
-        }
-
-        public TelephonyEvent[] newArray(int size) {
-            return new TelephonyEvent[size];
-        }
-    };
-
-    /** Implement the Parcelable interface */
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    /** Implement the Parcelable interface */
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeLong(timestamp);
-        dest.writeInt(phoneId);
-        dest.writeInt(tag);
-        dest.writeInt(param1);
-        dest.writeInt(param2);
-        dest.writeBundle(data);
-    }
-
-    public String toString() {
-        return String.format("%d,%d,%d,%d,%d,%s",
-                timestamp, phoneId, tag, param1, param2, data);
-    }
-}
diff --git a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
index 6c8be39..a4aab7c 100644
--- a/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
+++ b/tests/StatusBar/src/com/android/statusbartest/NotificationTestList.java
@@ -25,6 +25,7 @@
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.drawable.BitmapDrawable;
+import android.media.AudioAttributes;
 import android.os.Bundle;
 import android.os.Vibrator;
 import android.os.Handler;
@@ -86,6 +87,28 @@
     }
 
     private Test[] mTests = new Test[] {
+            new Test("Phone call") {
+                public void run()
+                {
+                    Notification n = new Notification.Builder(NotificationTestList.this)
+                            .setSmallIcon(R.drawable.icon2)
+                            .setContentTitle("phone call")
+                            .setLights(0xff0000ff, 1, 0)
+                            .setDefaults(Notification.DEFAULT_LIGHTS|Notification.DEFAULT_VIBRATE)
+                            .setSound(Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" +
+                                    getPackageName() + "/raw/ringer"),
+                                    new AudioAttributes.Builder().setUsage(
+                                            AudioAttributes.USAGE_NOTIFICATION_RINGTONE).build())
+                            .setPriority(Notification.PRIORITY_MAX)
+                            .setVibrate(new long[] {
+                                    300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+                                    300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400,
+                                    300, 400, 300, 400, 300, 400, 300, 400, 300, 400, 300, 400 })
+                            .setFullScreenIntent(makeIntent2(), true)
+                            .build();
+                    mNM.notify(7001, n);
+                }
+            },
             new Test("Post a group") {
                 public void run()
                 {
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index 005a483..c1f0038 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -37,6 +37,8 @@
         final int parentLeft, parentTop;
         final Matrix matrix;
         final String className;
+        final float textSize;
+        final int textColor;
         final CharSequence text;
         final int scrollY;
         final int[] lineCharOffsets;
@@ -50,6 +52,8 @@
             this.parentTop = parentTop;
             this.matrix = new Matrix(matrix);
             this.className = node.getClassName();
+            this.textSize = node.getTextSize();
+            this.textColor = node.getTextColor();
             this.text = node.getText() != null ? node.getText() : node.getContentDescription();
             this.scrollY = node.getScrollY();
             this.lineCharOffsets = node.getTextLineCharOffsets();
@@ -113,7 +117,9 @@
             TextEntry te = mTextRects.get(i);
             Log.d(TAG, "View " + te.className + " " + te.bounds.toShortString()
                     + " in " + te.parentLeft + "," + te.parentTop
-                    + " matrix=" + te.matrix.toShortString() + ": "
+                    + " matrix=" + te.matrix.toShortString()
+                    + " size=" + te.textSize + " color=#" + Integer.toHexString(te.textColor)
+                    + ": "
                     + te.text);
             if (te.lineCharOffsets != null && te.lineBaselines != null) {
                 final int num = te.lineCharOffsets.length < te.lineBaselines.length
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
index 450334c..5767f11 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/MainInteractionSession.java
@@ -194,6 +194,18 @@
     }
 
     @Override
+    public void onHandleAssistSecondary(final Bundle data, final AssistStructure structure,
+            final AssistContent content, int index, int count) {
+        Log.i(TAG, "Got secondary activity assist data " + index + " of " + count);
+        Log.i(TAG, "Showing assist structure after a few seconds...");
+        mContentView.postDelayed(new Runnable() {
+            public void run() {
+                onHandleAssist(data, structure, content);
+            }
+        }, 2000 * index);
+    }
+
+    @Override
     public void onHandleScreenshot(Bitmap screenshot) {
         if (screenshot != null) {
             mScreenshot.setImageBitmap(screenshot);
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
index 308488a..e0d8249 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/BridgeRenderSession.java
@@ -24,6 +24,7 @@
 import com.android.ide.common.rendering.api.ViewInfo;
 import com.android.layoutlib.bridge.impl.RenderSessionImpl;
 import com.android.tools.layoutlib.java.System_Delegate;
+import com.android.util.PropertiesMap;
 
 import android.view.View;
 import android.view.ViewGroup;
@@ -70,6 +71,11 @@
     }
 
     @Override
+    public Map<Object, PropertiesMap> getDefaultProperties() {
+        return mSession.getDefaultProperties();
+    }
+
+    @Override
     public Result render(long timeout, boolean forceMeasure) {
         try {
             Bridge.prepareThread();
@@ -196,10 +202,6 @@
         }
     }
 
-    public RenderSessionImpl getSessionImpl() {
-        return mSession;
-    }
-
     /*package*/ BridgeRenderSession(RenderSessionImpl scene, Result lastResult) {
         mSession = scene;
         if (scene != null) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index fd95bd5..80e230c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -27,12 +27,13 @@
 import com.android.ide.common.rendering.api.StyleResourceValue;
 import com.android.layoutlib.bridge.Bridge;
 import com.android.layoutlib.bridge.BridgeConstants;
-import com.android.layoutlib.bridge.android.PropertiesMap.Property;
 import com.android.layoutlib.bridge.android.view.WindowManagerImpl;
 import com.android.layoutlib.bridge.impl.ParserFactory;
 import com.android.layoutlib.bridge.impl.Stack;
 import com.android.resources.ResourceType;
 import com.android.util.Pair;
+import com.android.util.PropertiesMap;
+import com.android.util.PropertiesMap.Property;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -153,7 +154,6 @@
     private IBinder mBinder;
     private PackageManager mPackageManager;
 
-
     /**
      * Some applications that target both pre API 17 and post API 17, set the newer attrs to
      * reference the older ones. For example, android:paddingStart will resolve to
@@ -276,8 +276,8 @@
         return mRenderResources;
     }
 
-    public PropertiesMap getDefaultPropMap(Object key) {
-        return mDefaultPropMaps.get(key);
+    public Map<Object, PropertiesMap> getDefaultProperties() {
+        return mDefaultPropMaps;
     }
 
     public Configuration getConfiguration() {
@@ -1862,7 +1862,6 @@
         return false;
     }
 
-
     /**
      * The cached value depends on
      * <ol>
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
deleted file mode 100644
index a38d579..0000000
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/PropertiesMap.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2016 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.layoutlib.bridge.android;
-
-import com.android.layoutlib.bridge.android.PropertiesMap.Property;
-
-import java.util.HashMap;
-
-/**
- * An alias used for the value in {@link BridgeContext#mDefaultPropMaps}
- */
-public class PropertiesMap extends HashMap<String, Property> {
-
-    public static class Property {
-        public final String resource;
-        public final String value;
-
-        public Property(String resource, String value) {
-            this.resource = resource;
-            this.value = value;
-        }
-    }
-}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
index 2d38831..0c53753 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderAction.java
@@ -286,7 +286,7 @@
         return mParams;
     }
 
-    public BridgeContext getContext() {
+    protected BridgeContext getContext() {
         return mContext;
     }
 
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 11fabc6..3ef568c 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -48,6 +48,7 @@
 import com.android.resources.ResourceType;
 import com.android.tools.layoutlib.java.System_Delegate;
 import com.android.util.Pair;
+import com.android.util.PropertiesMap;
 
 import android.animation.AnimationThread;
 import android.animation.Animator;
@@ -1415,6 +1416,10 @@
         return mSystemViewInfoList;
     }
 
+    public Map<Object, PropertiesMap> getDefaultProperties() {
+        return getContext().getDefaultProperties();
+    }
+
     public void setScene(RenderSession session) {
         mScene = session;
     }
diff --git a/wifi/java/android/net/wifi/WifiConfiguration.java b/wifi/java/android/net/wifi/WifiConfiguration.java
index fb2bdd4..b8ef150 100644
--- a/wifi/java/android/net/wifi/WifiConfiguration.java
+++ b/wifi/java/android/net/wifi/WifiConfiguration.java
@@ -1636,6 +1636,9 @@
             if (allowedKeyManagement.get(KeyMgmt.WPA_EAP)) {
                 keyMgmt = KeyMgmt.strings[KeyMgmt.WPA_EAP];
             }
+            if (allowedKeyManagement.get(KeyMgmt.OSEN)) {
+                keyMgmt = KeyMgmt.strings[KeyMgmt.OSEN];
+            }
             if (allowedKeyManagement.get(KeyMgmt.IEEE8021X)) {
                 keyMgmt += KeyMgmt.strings[KeyMgmt.IEEE8021X];
             }
diff --git a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
index 394934f..b614a86 100644
--- a/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
+++ b/wifi/java/android/net/wifi/WifiEnterpriseConfig.java
@@ -437,6 +437,7 @@
         switch (eapMethod) {
             /** Valid methods */
             case Eap.TLS:
+            case Eap.UNAUTH_TLS:
                 setPhase2Method(Phase2.NONE);
                 /* fall through */
             case Eap.PEAP:
diff --git a/wifi/java/android/net/wifi/WifiScanner.java b/wifi/java/android/net/wifi/WifiScanner.java
index f8c1ea3..1a8197c 100644
--- a/wifi/java/android/net/wifi/WifiScanner.java
+++ b/wifi/java/android/net/wifi/WifiScanner.java
@@ -687,7 +687,7 @@
         Bundle scanParams = new Bundle();
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
-        sAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
+        mAsyncChannel.sendMessage(CMD_START_BACKGROUND_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -700,7 +700,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_BACKGROUND_SCAN, 0, key);
     }
     /**
      * reports currently available scan results on appropriate listeners
@@ -708,7 +708,7 @@
      */
     public boolean getScanResults() {
         validateChannel();
-        Message reply = sAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
+        Message reply = mAsyncChannel.sendMessageSynchronously(CMD_GET_SCAN_RESULTS, 0);
         return reply.what == CMD_OP_SUCCEEDED;
     }
 
@@ -741,7 +741,7 @@
         Bundle scanParams = new Bundle();
         scanParams.putParcelable(SCAN_PARAMS_SCAN_SETTINGS_KEY, settings);
         scanParams.putParcelable(SCAN_PARAMS_WORK_SOURCE_KEY, workSource);
-        sAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
+        mAsyncChannel.sendMessage(CMD_START_SINGLE_SCAN, 0, key, scanParams);
     }
 
     /**
@@ -754,7 +754,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_SINGLE_SCAN, 0, key);
     }
 
     private void startPnoScan(ScanSettings scanSettings, PnoSettings pnoSettings, int key) {
@@ -764,7 +764,7 @@
         scanSettings.isPnoScan = true;
         pnoParams.putParcelable(PNO_PARAMS_SCAN_SETTINGS_KEY, scanSettings);
         pnoParams.putParcelable(PNO_PARAMS_PNO_SETTINGS_KEY, pnoSettings);
-        sAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
+        mAsyncChannel.sendMessage(CMD_START_PNO_SCAN, 0, key, pnoParams);
     }
     /**
      * Start wifi connected PNO scan
@@ -820,7 +820,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_PNO_SCAN, 0, key);
     }
 
     /** specifies information about an access point of interest */
@@ -956,7 +956,7 @@
         int key = addListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
+        mAsyncChannel.sendMessage(CMD_START_TRACKING_CHANGE, 0, key);
     }
 
     /**
@@ -968,14 +968,14 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
+        mAsyncChannel.sendMessage(CMD_STOP_TRACKING_CHANGE, 0, key);
     }
 
     /** @hide */
     @SystemApi
     public void configureWifiChange(WifiChangeSettings settings) {
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
+        mAsyncChannel.sendMessage(CMD_CONFIGURE_WIFI_CHANGE, 0, 0, settings);
     }
 
     /** interface to receive hotlist events on; use this on {@link #setHotlist} */
@@ -1060,7 +1060,7 @@
         HotlistSettings settings = new HotlistSettings();
         settings.bssidInfos = bssidInfos;
         settings.apLostThreshold = apLostThreshold;
-        sAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
+        mAsyncChannel.sendMessage(CMD_SET_HOTLIST, 0, key, settings);
     }
 
     /**
@@ -1072,7 +1072,7 @@
         int key = removeListener(listener);
         if (key == INVALID_KEY) return;
         validateChannel();
-        sAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
+        mAsyncChannel.sendMessage(CMD_RESET_HOTLIST, 0, key);
     }
 
 
@@ -1137,17 +1137,14 @@
     private IWifiScanner mService;
 
     private static final int INVALID_KEY = 0;
-    private static int sListenerKey = 1;
+    private int mListenerKey = 1;
 
-    private static final SparseArray sListenerMap = new SparseArray();
-    private static final Object sListenerMapLock = new Object();
+    private final SparseArray mListenerMap = new SparseArray();
+    private final Object mListenerMapLock = new Object();
 
-    private static AsyncChannel sAsyncChannel;
-    private static CountDownLatch sConnected;
-
-    private static final Object sThreadRefLock = new Object();
-    private static int sThreadRefCount;
-    private static Handler sInternalHandler;
+    private AsyncChannel mAsyncChannel;
+    private final CountDownLatch mConnected;
+    private final Handler mInternalHandler;
 
     /**
      * Create a new WifiScanner instance.
@@ -1156,10 +1153,11 @@
      * the standard {@link android.content.Context#WIFI_SERVICE Context.WIFI_SERVICE}.
      * @param context the application context
      * @param service the Binder interface
+     * @param looper the Looper used to deliver callbacks
      * @hide
      */
-    public WifiScanner(Context context, IWifiScanner service) {
-        this(context, service, null, true);
+    public WifiScanner(Context context, IWifiScanner service, Looper looper) {
+        this(context, service, looper, true);
     }
 
     /**
@@ -1167,8 +1165,7 @@
      *
      * @param context The application context.
      * @param service The IWifiScanner Binder interface
-     * @param looper Looper for running WifiScanner operations. If null, a handler thread will be
-     *          created for running WifiScanner operations.
+     * @param looper the Looper used to deliver callbacks
      * @param waitForConnection If true, this will not return until a connection to Wifi Scanner
      *          service is established.
      * @hide
@@ -1178,50 +1175,34 @@
             boolean waitForConnection) {
         mContext = context;
         mService = service;
-        init(looper, waitForConnection);
-    }
 
-    private void init(Looper looper, boolean waitForConnection) {
-        synchronized (sThreadRefLock) {
-            if (++sThreadRefCount == 1) {
-                Messenger messenger = null;
-                try {
-                    messenger = mService.getMessenger();
-                } catch (RemoteException e) {
-                    /* do nothing */
-                } catch (SecurityException e) {
-                    /* do nothing */
-                }
+        Messenger messenger = null;
+        try {
+            messenger = mService.getMessenger();
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
 
-                if (messenger == null) {
-                    sAsyncChannel = null;
-                    return;
-                }
+        if (messenger == null) {
+            throw new IllegalStateException("getMessenger() returned null!  This is invalid.");
+        }
 
-                sAsyncChannel = new AsyncChannel();
-                sConnected = new CountDownLatch(1);
+        mAsyncChannel = new AsyncChannel();
+        mConnected = new CountDownLatch(1);
 
-                if (looper == null) {
-                    HandlerThread thread = new HandlerThread("WifiScanner");
-                    thread.start();
-                    sInternalHandler = new ServiceHandler(thread.getLooper());
-                } else {
-                    sInternalHandler = new ServiceHandler(looper);
-                }
-                sAsyncChannel.connect(mContext, sInternalHandler, messenger);
-                if (waitForConnection) {
-                    try {
-                        sConnected.await();
-                    } catch (InterruptedException e) {
-                        Log.e(TAG, "interrupted wait at init");
-                    }
-                }
+        mInternalHandler = new ServiceHandler(looper);
+        mAsyncChannel.connect(mContext, mInternalHandler, messenger);
+        if (waitForConnection) {
+            try {
+                mConnected.await();
+            } catch (InterruptedException e) {
+                Log.e(TAG, "interrupted wait at init");
             }
         }
     }
 
     private void validateChannel() {
-        if (sAsyncChannel == null) throw new IllegalStateException(
+        if (mAsyncChannel == null) throw new IllegalStateException(
                 "No permission to access and change wifi or a bad initialization");
     }
 
@@ -1229,7 +1210,7 @@
     // send an error message to internal handler; Otherwise add the listener to the listener map and
     // return the key of the listener.
     private int addListener(ActionListener listener) {
-        synchronized (sListenerMap) {
+        synchronized (mListenerMapLock) {
             boolean keyExists = (getListenerKey(listener) != INVALID_KEY);
             // Note we need to put the listener into listener map even if it's a duplicate as the
             // internal handler will need the key to find the listener. In case of duplicates,
@@ -1239,7 +1220,7 @@
                 if (DBG) Log.d(TAG, "listener key already exists");
                 OperationResult operationResult = new OperationResult(REASON_DUPLICATE_REQEUST,
                         "Outstanding request with same key not stopped yet");
-                Message message = Message.obtain(sInternalHandler, CMD_OP_FAILED, 0, key,
+                Message message = Message.obtain(mInternalHandler, CMD_OP_FAILED, 0, key,
                         operationResult);
                 message.sendToTarget();
                 return INVALID_KEY;
@@ -1249,55 +1230,55 @@
         }
     }
 
-    private static int putListener(Object listener) {
+    private int putListener(Object listener) {
         if (listener == null) return INVALID_KEY;
         int key;
-        synchronized (sListenerMapLock) {
+        synchronized (mListenerMapLock) {
             do {
-                key = sListenerKey++;
+                key = mListenerKey++;
             } while (key == INVALID_KEY);
-            sListenerMap.put(key, listener);
+            mListenerMap.put(key, listener);
         }
         return key;
     }
 
-    private static Object getListener(int key) {
+    private Object getListener(int key) {
         if (key == INVALID_KEY) return null;
-        synchronized (sListenerMapLock) {
-            Object listener = sListenerMap.get(key);
+        synchronized (mListenerMapLock) {
+            Object listener = mListenerMap.get(key);
             return listener;
         }
     }
 
-    private static int getListenerKey(Object listener) {
+    private int getListenerKey(Object listener) {
         if (listener == null) return INVALID_KEY;
-        synchronized (sListenerMapLock) {
-            int index = sListenerMap.indexOfValue(listener);
+        synchronized (mListenerMapLock) {
+            int index = mListenerMap.indexOfValue(listener);
             if (index == -1) {
                 return INVALID_KEY;
             } else {
-                return sListenerMap.keyAt(index);
+                return mListenerMap.keyAt(index);
             }
         }
     }
 
-    private static Object removeListener(int key) {
+    private Object removeListener(int key) {
         if (key == INVALID_KEY) return null;
-        synchronized (sListenerMapLock) {
-            Object listener = sListenerMap.get(key);
-            sListenerMap.remove(key);
+        synchronized (mListenerMapLock) {
+            Object listener = mListenerMap.get(key);
+            mListenerMap.remove(key);
             return listener;
         }
     }
 
-    private static int removeListener(Object listener) {
+    private int removeListener(Object listener) {
         int key = getListenerKey(listener);
         if (key == INVALID_KEY) {
             Log.e(TAG, "listener cannot be found");
             return key;
         }
-        synchronized (sListenerMapLock) {
-            sListenerMap.remove(key);
+        synchronized (mListenerMapLock) {
+            mListenerMap.remove(key);
             return key;
         }
     }
@@ -1338,7 +1319,7 @@
                 };
     }
 
-    private static class ServiceHandler extends Handler {
+    private class ServiceHandler extends Handler {
         ServiceHandler(Looper looper) {
             super(looper);
         }
@@ -1347,14 +1328,14 @@
             switch (msg.what) {
                 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
                     if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
-                        sAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
+                        mAsyncChannel.sendMessage(AsyncChannel.CMD_CHANNEL_FULL_CONNECTION);
                     } else {
                         Log.e(TAG, "Failed to set up channel connection");
                         // This will cause all further async API calls on the WifiManager
                         // to fail and throw an exception
-                        sAsyncChannel = null;
+                        mAsyncChannel = null;
                     }
-                    sConnected.countDown();
+                    mConnected.countDown();
                     return;
                 case AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED:
                     return;
@@ -1362,7 +1343,7 @@
                     Log.e(TAG, "Channel connection lost");
                     // This will cause all further async API calls on the WifiManager
                     // to fail and throw an exception
-                    sAsyncChannel = null;
+                    mAsyncChannel = null;
                     getLooper().quit();
                     return;
             }