Merge "More logging for ANR track-down"
diff --git a/Android.mk b/Android.mk
index d3e1cf5..c1c74ea 100644
--- a/Android.mk
+++ b/Android.mk
@@ -226,7 +226,6 @@
 	core/java/android/service/carrier/ICarrierMessagingService.aidl \
 	core/java/android/service/gatekeeper/IGateKeeperService.aidl \
 	core/java/android/service/notification/INotificationListener.aidl \
-	core/java/android/service/notification/INotificationAssistant.aidl \
 	core/java/android/service/notification/IStatusBarNotificationHolder.aidl \
 	core/java/android/service/notification/IConditionListener.aidl \
 	core/java/android/service/notification/IConditionProvider.aidl \
@@ -262,7 +261,7 @@
 	core/java/android/view/IApplicationToken.aidl \
 	core/java/android/view/IAppTransitionAnimationSpecsFuture.aidl \
 	core/java/android/view/IAssetAtlas.aidl \
-	core/java/android/view/IDockDividerVisibilityListener.aidl \
+	core/java/android/view/IDockedStackListener.aidl \
 	core/java/android/view/IGraphicsStats.aidl \
 	core/java/android/view/IInputFilter.aidl \
 	core/java/android/view/IInputFilterHost.aidl \
diff --git a/api/current.txt b/api/current.txt
index 76e44cf..78de860 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -67,7 +67,6 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -4229,7 +4228,7 @@
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
     field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
     field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
     field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -5198,6 +5197,7 @@
     field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -5758,6 +5758,7 @@
     method public java.lang.String 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 int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
@@ -5778,6 +5779,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 boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5819,6 +5821,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 setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5843,6 +5846,7 @@
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
     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);
@@ -7568,11 +7572,12 @@
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
-  public class ContentProviderClient {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method public void close();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7586,7 +7591,7 @@
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean release();
+    method public deprecated boolean release();
     method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -9513,6 +9518,7 @@
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9571,8 +9577,8 @@
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9584,13 +9590,17 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
     field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+    field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+    field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10840,7 +10850,7 @@
     field public final int statusCode;
   }
 
-  public class DrmManagerClient {
+  public class DrmManagerClient implements java.lang.AutoCloseable {
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10850,6 +10860,7 @@
     method public int checkRightsStatus(android.net.Uri);
     method public int checkRightsStatus(java.lang.String, int);
     method public int checkRightsStatus(android.net.Uri, int);
+    method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public java.lang.String[] getAvailableDrmEngines();
@@ -10863,7 +10874,7 @@
     method public java.lang.String getOriginalMimeType(android.net.Uri);
     method public int openConvertSession(java.lang.String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public void release();
+    method public deprecated void release();
     method public int removeAllRights();
     method public int removeRights(java.lang.String);
     method public int removeRights(android.net.Uri);
@@ -11267,14 +11278,14 @@
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public void requestCancelDecode();
+    method public deprecated void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public boolean inDither;
+    field public deprecated boolean inDither;
     field public deprecated boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public boolean inPreferQualityOverSpeed;
+    field public deprecated boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
     field public deprecated boolean inPurgeable;
@@ -18243,7 +18254,6 @@
     method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public static int getDefaultTimeZoneType();
     method public final java.lang.String getDisplayName();
     method public final java.lang.String getDisplayName(java.util.Locale);
     method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18267,8 +18277,6 @@
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(android.icu.util.TimeZone);
-    method public static synchronized void setDefaultTimeZoneType(int);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
@@ -18281,8 +18289,6 @@
     field public static final int SHORT_COMMONLY_USED = 6; // 0x6
     field public static final int SHORT_GENERIC = 2; // 0x2
     field public static final int SHORT_GMT = 4; // 0x4
-    field public static final int TIMEZONE_ICU = 0; // 0x0
-    field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
     field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
@@ -18378,8 +18384,6 @@
     method public static java.lang.String getVariant(java.lang.String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
     method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
     method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String toLanguageTag();
@@ -33102,6 +33106,7 @@
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
+    method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
 
 }
@@ -33494,20 +33499,13 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public class NotificationAdjustment implements android.os.Parcelable {
-    ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
-  }
-
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
     method public final void clearAnnotation(java.lang.String);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
     method public void onNotificationRemoved(java.lang.String, long, int);
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -33527,6 +33525,10 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
+  public class NotificationAssistantService.Adjustment {
+    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -33560,6 +33562,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
   }
 
   public static class NotificationListenerService.Ranking {
@@ -33631,10 +33634,13 @@
     method public void onClick();
     method public void onStartListening();
     method public void onStopListening();
-    method public void onTileAdded();
+    method public int onTileAdded();
     method public void onTileRemoved();
+    method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+    field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
 
 }
@@ -34895,6 +34901,7 @@
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_WIFI = 8; // 0x8
+    field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
 
   public final class CallAudioState implements android.os.Parcelable {
diff --git a/api/system-current.txt b/api/system-current.txt
index 27a16bf..24d257d4 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -93,7 +93,6 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
     field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
@@ -4349,7 +4348,7 @@
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
     field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
     field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
     field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -5318,6 +5317,7 @@
     field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -5886,6 +5886,7 @@
     method public java.lang.String 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 int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
@@ -5910,6 +5911,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 boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5953,6 +5955,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 setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5977,6 +5980,7 @@
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
     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);
@@ -7811,11 +7815,12 @@
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
-  public class ContentProviderClient {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method public void close();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7829,7 +7834,7 @@
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean release();
+    method public deprecated boolean release();
     method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -9550,12 +9555,6 @@
     method public abstract void onPackagesUnavailable(java.lang.String[], android.os.UserHandle, boolean);
   }
 
-  public class ManifestDigest implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.content.pm.ManifestDigest> CREATOR;
-  }
-
   public class PackageInfo implements android.os.Parcelable {
     ctor public PackageInfo();
     method public int describeContents();
@@ -9829,6 +9828,7 @@
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9887,8 +9887,8 @@
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9900,7 +9900,7 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int INSTALL_FAILED_ALREADY_EXISTS = -1; // 0xffffffff
     field public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13; // 0xfffffff3
@@ -9941,9 +9941,13 @@
     field public static final int MASK_PERMISSION_FLAGS = 255; // 0xff
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
     field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+    field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+    field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -11200,7 +11204,7 @@
     field public final int statusCode;
   }
 
-  public class DrmManagerClient {
+  public class DrmManagerClient implements java.lang.AutoCloseable {
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
@@ -11210,6 +11214,7 @@
     method public int checkRightsStatus(android.net.Uri);
     method public int checkRightsStatus(java.lang.String, int);
     method public int checkRightsStatus(android.net.Uri, int);
+    method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public java.lang.String[] getAvailableDrmEngines();
@@ -11223,7 +11228,7 @@
     method public java.lang.String getOriginalMimeType(android.net.Uri);
     method public int openConvertSession(java.lang.String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public void release();
+    method public deprecated void release();
     method public int removeAllRights();
     method public int removeRights(java.lang.String);
     method public int removeRights(android.net.Uri);
@@ -11627,14 +11632,14 @@
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public void requestCancelDecode();
+    method public deprecated void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public boolean inDither;
+    field public deprecated boolean inDither;
     field public deprecated boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public boolean inPreferQualityOverSpeed;
+    field public deprecated boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
     field public deprecated boolean inPurgeable;
@@ -19230,7 +19235,6 @@
     method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public static int getDefaultTimeZoneType();
     method public final java.lang.String getDisplayName();
     method public final java.lang.String getDisplayName(java.util.Locale);
     method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -19254,8 +19258,6 @@
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(android.icu.util.TimeZone);
-    method public static synchronized void setDefaultTimeZoneType(int);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
@@ -19268,8 +19270,6 @@
     field public static final int SHORT_COMMONLY_USED = 6; // 0x6
     field public static final int SHORT_GENERIC = 2; // 0x2
     field public static final int SHORT_GMT = 4; // 0x4
-    field public static final int TIMEZONE_ICU = 0; // 0x0
-    field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
     field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
@@ -19365,8 +19365,6 @@
     method public static java.lang.String getVariant(java.lang.String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
     method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
     method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String toLanguageTag();
@@ -35244,6 +35242,7 @@
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
+    method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
 
 }
@@ -35636,20 +35635,13 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public class NotificationAdjustment implements android.os.Parcelable {
-    ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
-  }
-
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
     method public final void clearAnnotation(java.lang.String);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
     method public void onNotificationRemoved(java.lang.String, long, int);
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -35669,6 +35661,10 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
+  public class NotificationAssistantService.Adjustment {
+    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -35707,6 +35703,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public static final int TRIM_FULL = 0; // 0x0
     field public static final int TRIM_LIGHT = 1; // 0x1
   }
@@ -35805,10 +35802,13 @@
     method public void onClick();
     method public void onStartListening();
     method public void onStopListening();
-    method public void onTileAdded();
+    method public int onTileAdded();
     method public void onTileRemoved();
+    method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+    field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
 
 }
@@ -37112,6 +37112,7 @@
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_WIFI = 8; // 0x8
+    field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
 
   public static abstract deprecated class Call.Listener extends android.telecom.Call.Callback {
diff --git a/api/test-current.txt b/api/test-current.txt
index cee8fad..6b6bafb 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -67,7 +67,6 @@
     field public static final java.lang.String DUMP = "android.permission.DUMP";
     field public static final java.lang.String EXPAND_STATUS_BAR = "android.permission.EXPAND_STATUS_BAR";
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
-    field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
     field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -4229,7 +4228,7 @@
     field public static final java.lang.String COLUMN_DESCRIPTION = "description";
     field public static final java.lang.String COLUMN_ID = "_id";
     field public static final java.lang.String COLUMN_LAST_MODIFIED_TIMESTAMP = "last_modified_timestamp";
-    field public static final java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
+    field public static final deprecated java.lang.String COLUMN_LOCAL_FILENAME = "local_filename";
     field public static final java.lang.String COLUMN_LOCAL_URI = "local_uri";
     field public static final java.lang.String COLUMN_MEDIAPROVIDER_URI = "mediaprovider_uri";
     field public static final java.lang.String COLUMN_MEDIA_TYPE = "media_type";
@@ -5198,6 +5197,7 @@
     field public static final int SUPPRESSED_EFFECTS_UNSET = -1; // 0xffffffff
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
     field public final int priorityCallSenders;
     field public final int priorityCategories;
     field public final int priorityMessageSenders;
@@ -5758,6 +5758,7 @@
     method public java.lang.String 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 int getMaximumFailedPasswordsForWipe(android.content.ComponentName);
     method public long getMaximumTimeToLock(android.content.ComponentName);
     method public boolean getPackageSuspended(android.content.ComponentName, java.lang.String);
@@ -5778,6 +5779,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 boolean getStorageEncryption(android.content.ComponentName);
     method public int getStorageEncryptionStatus();
     method public android.app.admin.SystemUpdatePolicy getSystemUpdatePolicy();
@@ -5819,6 +5821,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 setMasterVolumeMuted(android.content.ComponentName, boolean);
     method public void setMaximumFailedPasswordsForWipe(android.content.ComponentName, int);
     method public void setMaximumTimeToLock(android.content.ComponentName, long);
@@ -5843,6 +5846,7 @@
     method public void setRestrictionsProvider(android.content.ComponentName, android.content.ComponentName);
     method public void setScreenCaptureDisabled(android.content.ComponentName, boolean);
     method public void setSecureSetting(android.content.ComponentName, java.lang.String, java.lang.String);
+    method public void setShortSupportMessage(android.content.ComponentName, java.lang.String);
     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);
@@ -7568,11 +7572,12 @@
     method public abstract void writeDataToPipe(android.os.ParcelFileDescriptor, android.net.Uri, java.lang.String, android.os.Bundle, T);
   }
 
-  public class ContentProviderClient {
+  public class ContentProviderClient implements java.lang.AutoCloseable {
     method public android.content.ContentProviderResult[] applyBatch(java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
     method public int bulkInsert(android.net.Uri, android.content.ContentValues[]) throws android.os.RemoteException;
     method public android.os.Bundle call(java.lang.String, java.lang.String, android.os.Bundle) throws android.os.RemoteException;
     method public final android.net.Uri canonicalize(android.net.Uri) throws android.os.RemoteException;
+    method public void close();
     method public int delete(android.net.Uri, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
     method public android.content.ContentProvider getLocalContentProvider();
     method public java.lang.String[] getStreamTypes(android.net.Uri, java.lang.String) throws android.os.RemoteException;
@@ -7586,7 +7591,7 @@
     method public final android.content.res.AssetFileDescriptor openTypedAssetFileDescriptor(android.net.Uri, java.lang.String, android.os.Bundle, android.os.CancellationSignal) throws java.io.FileNotFoundException, android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String) throws android.os.RemoteException;
     method public android.database.Cursor query(android.net.Uri, java.lang.String[], java.lang.String, java.lang.String[], java.lang.String, android.os.CancellationSignal) throws android.os.RemoteException;
-    method public boolean release();
+    method public deprecated boolean release();
     method public final android.net.Uri uncanonicalize(android.net.Uri) throws android.os.RemoteException;
     method public int update(android.net.Uri, android.content.ContentValues, java.lang.String, java.lang.String[]) throws android.os.RemoteException;
   }
@@ -9513,6 +9518,7 @@
     field public static final java.lang.String FEATURE_CONNECTION_SERVICE = "android.software.connectionservice";
     field public static final java.lang.String FEATURE_CONSUMER_IR = "android.hardware.consumerir";
     field public static final java.lang.String FEATURE_DEVICE_ADMIN = "android.software.device_admin";
+    field public static final java.lang.String FEATURE_ETHERNET = "android.hardware.ethernet";
     field public static final java.lang.String FEATURE_FAKETOUCH = "android.hardware.faketouch";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_DISTINCT = "android.hardware.faketouch.multitouch.distinct";
     field public static final java.lang.String FEATURE_FAKETOUCH_MULTITOUCH_JAZZHAND = "android.hardware.faketouch.multitouch.jazzhand";
@@ -9571,8 +9577,8 @@
     field public static final java.lang.String FEATURE_WIFI_DIRECT = "android.hardware.wifi.direct";
     field public static final int GET_ACTIVITIES = 1; // 0x1
     field public static final int GET_CONFIGURATIONS = 16384; // 0x4000
-    field public static final int GET_DISABLED_COMPONENTS = 512; // 0x200
-    field public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final deprecated int GET_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final deprecated int GET_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
     field public static final int GET_GIDS = 256; // 0x100
     field public static final int GET_INSTRUMENTATION = 16; // 0x10
     field public static final int GET_INTENT_FILTERS = 32; // 0x20
@@ -9584,13 +9590,17 @@
     field public static final int GET_SERVICES = 4; // 0x4
     field public static final int GET_SHARED_LIBRARY_FILES = 1024; // 0x400
     field public static final int GET_SIGNATURES = 64; // 0x40
-    field public static final int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
+    field public static final deprecated int GET_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final int GET_URI_PERMISSION_PATTERNS = 2048; // 0x800
     field public static final int MATCH_ALL = 131072; // 0x20000
     field public static final int MATCH_DEFAULT_ONLY = 65536; // 0x10000
+    field public static final int MATCH_DISABLED_COMPONENTS = 512; // 0x200
+    field public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 32768; // 0x8000
+    field public static final int MATCH_ENCRYPTION_AWARE = 524288; // 0x80000
     field public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = 786432; // 0xc0000
-    field public static final int MATCH_ENCRYPTION_AWARE_ONLY = 524288; // 0x80000
-    field public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 262144; // 0x40000
+    field public static final int MATCH_ENCRYPTION_UNAWARE = 262144; // 0x40000
+    field public static final int MATCH_SYSTEM_ONLY = 1048576; // 0x100000
+    field public static final int MATCH_UNINSTALLED_PACKAGES = 8192; // 0x2000
     field public static final long MAXIMUM_VERIFICATION_TIMEOUT = 3600000L; // 0x36ee80L
     field public static final int PERMISSION_DENIED = -1; // 0xffffffff
     field public static final int PERMISSION_GRANTED = 0; // 0x0
@@ -10840,7 +10850,7 @@
     field public final int statusCode;
   }
 
-  public class DrmManagerClient {
+  public class DrmManagerClient implements java.lang.AutoCloseable {
     ctor public DrmManagerClient(android.content.Context);
     method public android.drm.DrmInfo acquireDrmInfo(android.drm.DrmInfoRequest);
     method public int acquireRights(android.drm.DrmInfoRequest);
@@ -10850,6 +10860,7 @@
     method public int checkRightsStatus(android.net.Uri);
     method public int checkRightsStatus(java.lang.String, int);
     method public int checkRightsStatus(android.net.Uri, int);
+    method public void close();
     method public android.drm.DrmConvertedStatus closeConvertSession(int);
     method public android.drm.DrmConvertedStatus convertData(int, byte[]);
     method public java.lang.String[] getAvailableDrmEngines();
@@ -10863,7 +10874,7 @@
     method public java.lang.String getOriginalMimeType(android.net.Uri);
     method public int openConvertSession(java.lang.String);
     method public int processDrmInfo(android.drm.DrmInfo);
-    method public void release();
+    method public deprecated void release();
     method public int removeAllRights();
     method public int removeRights(java.lang.String);
     method public int removeRights(android.net.Uri);
@@ -11267,14 +11278,14 @@
 
   public static class BitmapFactory.Options {
     ctor public BitmapFactory.Options();
-    method public void requestCancelDecode();
+    method public deprecated void requestCancelDecode();
     field public android.graphics.Bitmap inBitmap;
     field public int inDensity;
-    field public boolean inDither;
+    field public deprecated boolean inDither;
     field public deprecated boolean inInputShareable;
     field public boolean inJustDecodeBounds;
     field public boolean inMutable;
-    field public boolean inPreferQualityOverSpeed;
+    field public deprecated boolean inPreferQualityOverSpeed;
     field public android.graphics.Bitmap.Config inPreferredConfig;
     field public boolean inPremultiplied;
     field public deprecated boolean inPurgeable;
@@ -18243,7 +18254,6 @@
     method public static java.lang.String getCanonicalID(java.lang.String, boolean[]);
     method public int getDSTSavings();
     method public static android.icu.util.TimeZone getDefault();
-    method public static int getDefaultTimeZoneType();
     method public final java.lang.String getDisplayName();
     method public final java.lang.String getDisplayName(java.util.Locale);
     method public final java.lang.String getDisplayName(android.icu.util.ULocale);
@@ -18267,8 +18277,6 @@
     method public abstract boolean inDaylightTime(java.util.Date);
     method public boolean isFrozen();
     method public boolean observesDaylightTime();
-    method public static synchronized void setDefault(android.icu.util.TimeZone);
-    method public static synchronized void setDefaultTimeZoneType(int);
     method public void setID(java.lang.String);
     method public abstract void setRawOffset(int);
     method public abstract boolean useDaylightTime();
@@ -18281,8 +18289,6 @@
     field public static final int SHORT_COMMONLY_USED = 6; // 0x6
     field public static final int SHORT_GENERIC = 2; // 0x2
     field public static final int SHORT_GMT = 4; // 0x4
-    field public static final int TIMEZONE_ICU = 0; // 0x0
-    field public static final int TIMEZONE_JDK = 1; // 0x1
     field public static final android.icu.util.TimeZone UNKNOWN_ZONE;
     field public static final java.lang.String UNKNOWN_ZONE_ID = "Etc/Unknown";
   }
@@ -18378,8 +18384,6 @@
     method public static java.lang.String getVariant(java.lang.String);
     method public boolean isRightToLeft();
     method public static android.icu.util.ULocale minimizeSubtags(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale);
-    method public static synchronized void setDefault(android.icu.util.ULocale.Category, android.icu.util.ULocale);
     method public android.icu.util.ULocale setKeywordValue(java.lang.String, java.lang.String);
     method public static java.lang.String setKeywordValue(java.lang.String, java.lang.String, java.lang.String);
     method public java.lang.String toLanguageTag();
@@ -33105,6 +33109,7 @@
   public class NetworkSecurityPolicy {
     method public static android.security.NetworkSecurityPolicy getInstance();
     method public boolean isCleartextTrafficPermitted();
+    method public boolean isCleartextTrafficPermitted(java.lang.String);
   }
 
 }
@@ -33497,20 +33502,13 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.ConditionProviderService";
   }
 
-  public class NotificationAdjustment implements android.os.Parcelable {
-    ctor public NotificationAdjustment(int, java.lang.CharSequence, android.net.Uri);
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator<android.service.notification.NotificationAdjustment> CREATOR;
-  }
-
   public abstract class NotificationAssistantService extends android.service.notification.NotificationListenerService {
     ctor public NotificationAssistantService();
-    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAdjustment);
+    method public final void adjustImportance(java.lang.String, android.service.notification.NotificationAssistantService.Adjustment);
     method public final void clearAnnotation(java.lang.String);
     method public void onNotificationActionClick(java.lang.String, long, int);
     method public void onNotificationClick(java.lang.String, long);
-    method public abstract android.service.notification.NotificationAdjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
+    method public abstract android.service.notification.NotificationAssistantService.Adjustment onNotificationEnqueued(android.service.notification.StatusBarNotification, int, boolean);
     method public void onNotificationRemoved(java.lang.String, long, int);
     method public void onNotificationVisibilityChanged(java.lang.String, long, boolean);
     method public final void setAnnotation(java.lang.String, android.app.Notification);
@@ -33530,6 +33528,10 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationAssistantService";
   }
 
+  public class NotificationAssistantService.Adjustment {
+    ctor public NotificationAssistantService.Adjustment(int, java.lang.CharSequence, android.net.Uri);
+  }
+
   public abstract class NotificationListenerService extends android.app.Service {
     ctor public NotificationListenerService();
     method public final void cancelAllNotifications();
@@ -33563,6 +33565,7 @@
     field public static final java.lang.String SERVICE_INTERFACE = "android.service.notification.NotificationListenerService";
     field public static final int SUPPRESSED_EFFECT_LIGHTS = 1; // 0x1
     field public static final int SUPPRESSED_EFFECT_PEEK = 2; // 0x2
+    field public static final int SUPPRESSED_EFFECT_SCREEN_ON = 4; // 0x4
   }
 
   public static class NotificationListenerService.Ranking {
@@ -33634,10 +33637,13 @@
     method public void onClick();
     method public void onStartListening();
     method public void onStopListening();
-    method public void onTileAdded();
+    method public int onTileAdded();
     method public void onTileRemoved();
+    method public static final void requestListeningState(android.content.Context, android.content.ComponentName);
     method public final void showDialog(android.app.Dialog);
     field public static final java.lang.String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
+    field public static final int TILE_MODE_ACTIVE = 2; // 0x2
+    field public static final int TILE_MODE_PASSIVE = 1; // 0x1
   }
 
 }
@@ -34898,6 +34904,7 @@
     field public static final int PROPERTY_GENERIC_CONFERENCE = 2; // 0x2
     field public static final int PROPERTY_HIGH_DEF_AUDIO = 16; // 0x10
     field public static final int PROPERTY_WIFI = 8; // 0x8
+    field public static final int PROPERTY_WORK_CALL = 32; // 0x20
   }
 
   public final class CallAudioState implements android.os.Parcelable {
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 4f7a109..6302d74 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -159,6 +159,7 @@
                 "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "       am stack resize-docked-stack <LEFT,TOP,RIGHT,BOTTOM> [<TASK_LEFT,TASK_TOP,TASK_RIGHT,TASK_BOTTOM>]\n" +
                 "       am stack size-docked-stack-test: <STEP_SIZE> <l|t|r|b> [DELAY_MS]\n" +
                 "       am stack move-top-activity-to-pinned-stack: <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "       am stack positiontask <TASK_ID> <STACK_ID> <POSITION>\n" +
@@ -299,7 +300,11 @@
                 "am stack movetask: move <TASK_ID> from its current stack to the top (true) or" +
                 "   bottom (false) of <STACK_ID>.\n" +
                 "\n" +
-                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>." +
+                "am stack resize: change <STACK_ID> size and position to <LEFT,TOP,RIGHT,BOTTOM>.\n" +
+                "\n" +
+                "am stack resize-docked-stack: change docked stack to <LEFT,TOP,RIGHT,BOTTOM>\n" +
+                "   and supplying temporary different task bounds indicated by\n" +
+                "   <TASK_LEFT,TOP,RIGHT,BOTTOM>\n" +
                 "\n" +
                 "am stack size-docked-stack-test: test command for sizing docked stack by\n" +
                 "   <STEP_SIZE> increments from the side <l>eft, <t>op, <r>ight, or <b>ottom\n" +
@@ -1683,6 +1688,9 @@
             case "resize":
                 runStackResize();
                 break;
+            case "resize-docked-stack":
+                runStackResizeDocked();
+                break;
             case "positiontask":
                 runStackPositionTask();
                 break;
@@ -1751,6 +1759,20 @@
         resizeStack(stackId, bounds, 0);
     }
 
+    private void runStackResizeDocked() throws Exception {
+        final Rect bounds = getBounds();
+        final Rect taskBounds = getBounds();
+        if (bounds == null || taskBounds == null) {
+            System.err.println("Error: invalid input bounds");
+            return;
+        }
+        try {
+            mAm.resizeDockedStack(bounds, taskBounds, null, null, null);
+        } catch (RemoteException e) {
+            showError("Error: resizing docked stack " + e);
+        }
+    }
+
     private void resizeStack(int stackId, Rect bounds, int delayMs) throws Exception {
         if (bounds == null) {
             showError("Error: invalid input bounds");
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3e6b595..6fc0d74 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1082,6 +1082,10 @@
         return false;
     }
 
+    /** @hide */
+    public void onDestroy() {
+    }
+
     /**
      * Common implementation for requestFocus that takes in the Toolbar and moves focus
      * to the contents. This makes the ViewGroups containing the toolbar allow focus while it stays
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 800ebc6..8346161 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -1703,6 +1703,10 @@
             mSearchManager.stopSearch();
         }
 
+        if (mActionBar != null) {
+            mActionBar.onDestroy();
+        }
+
         getApplication().dispatchActivityDestroyed(this);
     }
 
@@ -2208,14 +2212,22 @@
      * @param toolbar Toolbar to set as the Activity's action bar
      */
     public void setActionBar(@Nullable Toolbar toolbar) {
-        if (getActionBar() instanceof WindowDecorActionBar) {
+        final ActionBar ab = getActionBar();
+        if (ab instanceof WindowDecorActionBar) {
             throw new IllegalStateException("This Activity already has an action bar supplied " +
                     "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
                     "android:windowActionBar to false in your theme to use a Toolbar instead.");
         }
-        // Clear out the MenuInflater to make sure that it is valid for the new Action Bar
+
+        // If we reach here then we're setting a new action bar
+        // First clear out the MenuInflater to make sure that it is valid for the new Action Bar
         mMenuInflater = null;
 
+        // If we have an action bar currently, destroy it
+        if (ab != null) {
+            ab.onDestroy();
+        }
+
         ToolbarActionBar tbab = new ToolbarActionBar(toolbar, getTitle(), this);
         mActionBar = tbab;
         mWindow.setCallback(tbab.getWrappedWindowCallback());
diff --git a/core/java/android/app/ActivityManagerNative.java b/core/java/android/app/ActivityManagerNative.java
index 3a3aa92..da21099 100644
--- a/core/java/android/app/ActivityManagerNative.java
+++ b/core/java/android/app/ActivityManagerNative.java
@@ -332,10 +332,9 @@
         {
             data.enforceInterface(IActivityManager.descriptor);
             final int taskId = data.readInt();
-            final int launchStackId = data.readInt();
             final Bundle options =
                     data.readInt() == 0 ? null : Bundle.CREATOR.createFromParcel(data);
-            final int result = startActivityFromRecents(taskId, launchStackId, options);
+            final int result = startActivityFromRecents(taskId, options);
             reply.writeNoException();
             reply.writeInt(result);
             return true;
@@ -571,6 +570,14 @@
             return true;
         }
 
+        case ACTIVITY_RELAUNCHED_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            IBinder token = data.readStrongBinder();
+            activityRelaunched(token);
+            reply.writeNoException();
+            return true;
+        }
+
         case GET_CALLING_PACKAGE_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             IBinder token = data.readStrongBinder();
@@ -786,6 +793,39 @@
             return true;
         }
 
+        case RESIZE_DOCKED_STACK_TRANSACTION: {
+            data.enforceInterface(IActivityManager.descriptor);
+            final boolean hasBounds = data.readInt() != 0;
+            Rect bounds = null;
+            if (hasBounds) {
+                bounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempDockedTaskBounds = data.readInt() != 0;
+            Rect tempDockedTaskBounds = null;
+            if (hasTempDockedTaskBounds) {
+                tempDockedTaskBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempDockedTaskInsetBounds = data.readInt() != 0;
+            Rect tempDockedTaskInsetBounds = null;
+            if (hasTempDockedTaskInsetBounds) {
+                tempDockedTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempOtherTaskBounds = data.readInt() != 0;
+            Rect tempOtherTaskBounds = null;
+            if (hasTempOtherTaskBounds) {
+                tempOtherTaskBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            final boolean hasTempOtherTaskInsetBounds = data.readInt() != 0;
+            Rect tempOtherTaskInsetBounds = null;
+            if (hasTempOtherTaskInsetBounds) {
+                tempOtherTaskInsetBounds = Rect.CREATOR.createFromParcel(data);
+            }
+            resizeDockedStack(bounds, tempDockedTaskBounds, tempDockedTaskInsetBounds,
+                    tempOtherTaskBounds, tempOtherTaskInsetBounds);
+            reply.writeNoException();
+            return true;
+        }
+
         case POSITION_TASK_IN_STACK_TRANSACTION: {
             data.enforceInterface(IActivityManager.descriptor);
             int taskId = data.readInt();
@@ -3088,13 +3128,12 @@
         data.recycle();
         return result != 0;
     }
-    public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+    public int startActivityFromRecents(int taskId, Bundle options)
             throws RemoteException {
         Parcel data = Parcel.obtain();
         Parcel reply = Parcel.obtain();
         data.writeInterfaceToken(IActivityManager.descriptor);
         data.writeInt(taskId);
-        data.writeInt(launchStackId);
         if (options == null) {
             data.writeInt(0);
         } else {
@@ -3382,6 +3421,17 @@
         data.recycle();
         reply.recycle();
     }
+    public void activityRelaunched(IBinder token) throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        data.writeStrongBinder(token);
+        mRemote.transact(ACTIVITY_RELAUNCHED_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
     public String getCallingPackage(IBinder token) throws RemoteException
     {
         Parcel data = Parcel.obtain();
@@ -3692,6 +3742,50 @@
         reply.recycle();
     }
     @Override
+    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds)
+            throws RemoteException
+    {
+        Parcel data = Parcel.obtain();
+        Parcel reply = Parcel.obtain();
+        data.writeInterfaceToken(IActivityManager.descriptor);
+        if (dockedBounds != null) {
+            data.writeInt(1);
+            dockedBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempDockedTaskBounds != null) {
+            data.writeInt(1);
+            tempDockedTaskBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempDockedTaskInsetBounds != null) {
+            data.writeInt(1);
+            tempDockedTaskInsetBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempOtherTaskBounds != null) {
+            data.writeInt(1);
+            tempOtherTaskBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        if (tempOtherTaskInsetBounds != null) {
+            data.writeInt(1);
+            tempOtherTaskInsetBounds.writeToParcel(data, 0);
+        } else {
+            data.writeInt(0);
+        }
+        mRemote.transact(RESIZE_DOCKED_STACK_TRANSACTION, data, reply, 0);
+        reply.readException();
+        data.recycle();
+        reply.recycle();
+    }
+    @Override
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException
     {
         Parcel data = Parcel.obtain();
diff --git a/core/java/android/app/ActivityOptions.java b/core/java/android/app/ActivityOptions.java
index cee1aa5..e596a68 100644
--- a/core/java/android/app/ActivityOptions.java
+++ b/core/java/android/app/ActivityOptions.java
@@ -17,6 +17,7 @@
 package android.app;
 
 import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 
 import android.content.Context;
 import android.content.Intent;
@@ -67,7 +68,8 @@
      * The bounds (window size) that the activity should be launched in. Set to null explicitly for
      * full screen. If the key is not found, previous bounds will be preserved.
      * NOTE: This value is ignored on devices that don't have
-     * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} enabled.
+     * {@link android.content.pm.PackageManager#FEATURE_FREEFORM_WINDOW_MANAGEMENT} or
+     * {@link android.content.pm.PackageManager#FEATURE_PICTURE_IN_PICTURE} enabled.
      * @hide
      */
     public static final String KEY_LAUNCH_BOUNDS = "android:activity.launchBounds";
@@ -145,6 +147,12 @@
     private static final String KEY_ANIM_SPECS = "android:activity.animSpecs";
 
     /**
+     * The stack id the activity should be launched into.
+     * @hide
+     */
+    private static final String KEY_LAUNCH_STACK_ID = "android.activity.launchStackId";
+
+    /**
      * Where the docked stack should be positioned.
      * @hide
      */
@@ -215,6 +223,7 @@
     private int mResultCode;
     private int mExitCoordinatorIndex;
     private PendingIntent mUsageTimeReport;
+    private int mLaunchStackId = INVALID_STACK_ID;
     private int mDockCreateMode = DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
     private AppTransitionAnimationSpec mAnimSpecs[];
 
@@ -754,6 +763,7 @@
                 mExitCoordinatorIndex = opts.getInt(KEY_EXIT_COORDINATOR_INDEX);
                 break;
         }
+        mLaunchStackId = opts.getInt(KEY_LAUNCH_STACK_ID, INVALID_STACK_ID);
         mDockCreateMode = opts.getInt(KEY_DOCK_CREATE_MODE, DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT);
         if (opts.containsKey(KEY_ANIM_SPECS)) {
             Parcelable[] specs = opts.getParcelableArray(KEY_ANIM_SPECS);
@@ -901,7 +911,19 @@
     }
 
     /** @hide */
-    public int getDockCreateMode() { return mDockCreateMode; }
+    public int getLaunchStackId() {
+        return mLaunchStackId;
+    }
+
+    /** @hide */
+    public void setLaunchStackId(int launchStackId) {
+        mLaunchStackId = launchStackId;
+    }
+
+    /** @hide */
+    public int getDockCreateMode() {
+        return mDockCreateMode;
+    }
 
     /** @hide */
     public void setDockCreateMode(int dockCreateMode) {
@@ -1049,6 +1071,7 @@
                 b.putInt(KEY_EXIT_COORDINATOR_INDEX, mExitCoordinatorIndex);
                 break;
         }
+        b.putInt(KEY_LAUNCH_STACK_ID, mLaunchStackId);
         b.putInt(KEY_DOCK_CREATE_MODE, mDockCreateMode);
         if (mAnimSpecs != null) {
             b.putParcelableArray(KEY_ANIM_SPECS, mAnimSpecs);
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index ed168d1..177fabe 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -4161,6 +4161,15 @@
                             r.pendingIntents = pendingNewIntents;
                         }
                     }
+
+                    // For each relaunch request, activity manager expects an answer
+                    if (!r.onlyLocalRequest && fromServer) {
+                        try {
+                            ActivityManagerNative.getDefault().activityRelaunched(token);
+                        } catch (RemoteException e) {
+                            e.printStackTrace();
+                        }
+                    }
                     break;
                 }
             }
@@ -4275,6 +4284,13 @@
         ActivityClientRecord r = mActivities.get(tmp.token);
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Handling relaunch of " + r);
         if (r == null) {
+            if (!tmp.onlyLocalRequest) {
+                try {
+                    ActivityManagerNative.getDefault().activityRelaunched(tmp.token);
+                } catch (RemoteException e) {
+                    // If the system process has died, it's game over for everyone.
+                }
+            }
             return;
         }
 
@@ -4320,6 +4336,14 @@
         r.overrideConfig = tmp.overrideConfig;
 
         handleLaunchActivity(r, currentIntent);
+
+        if (!tmp.onlyLocalRequest) {
+            try {
+                ActivityManagerNative.getDefault().activityRelaunched(r.token);
+            } catch (RemoteException e) {
+                // If the system process has died, it's game over for everyone.
+            }
+        }
     }
 
     private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
diff --git a/core/java/android/app/ApplicationPackageManager.java b/core/java/android/app/ApplicationPackageManager.java
index 77721e6..a60fbf6 100644
--- a/core/java/android/app/ApplicationPackageManager.java
+++ b/core/java/android/app/ApplicationPackageManager.java
@@ -42,7 +42,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -1421,7 +1420,7 @@
     public void installPackage(Uri packageURI, IPackageInstallObserver observer, int flags,
                                String installerPackageName) {
         final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID, null);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                 installerPackageName, verificationParams, null, mContext.getUserId());
     }
@@ -1429,9 +1428,9 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
         final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID, manifestDigest);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, new LegacyPackageInstallObserver(observer), flags,
                 installerPackageName, verificationParams, encryptionParams, mContext.getUserId());
     }
@@ -1455,7 +1454,7 @@
     public void installPackageAsUser(Uri packageURI, PackageInstallObserver observer, int flags,
                String installerPackageName, int userId) {
         final VerificationParams verificationParams = new VerificationParams(null, null,
-                null, VerificationParams.NO_UID, null);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, observer, flags, installerPackageName, verificationParams, null,
                 userId);
     }
@@ -1463,10 +1462,10 @@
     @Override
     public void installPackageWithVerification(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
+            Uri verificationURI,
             ContainerEncryptionParams encryptionParams) {
         final VerificationParams verificationParams = new VerificationParams(verificationURI, null,
-                null, VerificationParams.NO_UID, manifestDigest);
+                null, VerificationParams.NO_UID);
         installCommon(packageURI, observer, flags, installerPackageName, verificationParams,
                 encryptionParams, mContext.getUserId());
     }
diff --git a/core/java/android/app/BackStackRecord.java b/core/java/android/app/BackStackRecord.java
index 984a186..a147cc8 100644
--- a/core/java/android/app/BackStackRecord.java
+++ b/core/java/android/app/BackStackRecord.java
@@ -719,7 +719,7 @@
                     Fragment f = op.fragment;
                     int containerId = f.mContainerId;
                     if (mManager.mAdded != null) {
-                        for (int i = 0; i < mManager.mAdded.size(); i++) {
+                        for (int i = mManager.mAdded.size() - 1; i >= 0; i--) {
                             Fragment old = mManager.mAdded.get(i);
                             if (FragmentManagerImpl.DEBUG) {
                                 Log.v(TAG,
diff --git a/core/java/android/app/DownloadManager.java b/core/java/android/app/DownloadManager.java
index fb0e79b..a9516d0 100644
--- a/core/java/android/app/DownloadManager.java
+++ b/core/java/android/app/DownloadManager.java
@@ -27,6 +27,7 @@
 import android.net.ConnectivityManager;
 import android.net.NetworkPolicyManager;
 import android.net.Uri;
+import android.os.Build;
 import android.os.Environment;
 import android.os.ParcelFileDescriptor;
 import android.provider.Downloads;
@@ -105,8 +106,17 @@
     public final static String COLUMN_LOCAL_URI = "local_uri";
 
     /**
-     * The pathname of the file where the download is stored.
+     * Path to the downloaded file on disk.
+     * <p>
+     * Note that apps may not have filesystem permissions to directly access
+     * this path. Instead of trying to open this path directly, apps should use
+     * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain access.
+     *
+     * @deprecated apps should transition to using
+     *             {@link ContentResolver#openFileDescriptor(Uri, String)}
+     *             instead.
      */
+    @Deprecated
     public final static String COLUMN_LOCAL_FILENAME = "local_filename";
 
     /**
@@ -908,16 +918,19 @@
         }
     }
 
-    private ContentResolver mResolver;
-    private String mPackageName;
+    private final ContentResolver mResolver;
+    private final String mPackageName;
+    private final int mTargetSdkVersion;
+
     private Uri mBaseUri = Downloads.Impl.CONTENT_URI;
 
     /**
      * @hide
      */
-    public DownloadManager(ContentResolver resolver, String packageName) {
-        mResolver = resolver;
-        mPackageName = packageName;
+    public DownloadManager(Context context) {
+        mResolver = context.getContentResolver();
+        mPackageName = context.getPackageName();
+        mTargetSdkVersion = context.getApplicationInfo().targetSdkVersion;
     }
 
     /**
@@ -997,7 +1010,7 @@
         if (underlyingCursor == null) {
             return null;
         }
-        return new CursorTranslator(underlyingCursor, mBaseUri);
+        return new CursorTranslator(underlyingCursor, mBaseUri, mTargetSdkVersion);
     }
 
     /**
@@ -1265,11 +1278,13 @@
      * underlying data.
      */
     private static class CursorTranslator extends CursorWrapper {
-        private Uri mBaseUri;
+        private final Uri mBaseUri;
+        private final int mTargetSdkVersion;
 
-        public CursorTranslator(Cursor cursor, Uri baseUri) {
+        public CursorTranslator(Cursor cursor, Uri baseUri, int targetSdkVersion) {
             super(cursor);
             mBaseUri = baseUri;
+            mTargetSdkVersion = targetSdkVersion;
         }
 
         @Override
@@ -1290,8 +1305,19 @@
 
         @Override
         public String getString(int columnIndex) {
-            return (getColumnName(columnIndex).equals(COLUMN_LOCAL_URI)) ? getLocalUri() :
-                    super.getString(columnIndex);
+            final String columnName = getColumnName(columnIndex);
+            switch (columnName) {
+                case COLUMN_LOCAL_URI:
+                    return getLocalUri();
+                case COLUMN_LOCAL_FILENAME:
+                    if (mTargetSdkVersion >= Build.VERSION_CODES.N) {
+                        throw new IllegalArgumentException(
+                                "COLUMN_LOCAL_FILENAME is deprecated;"
+                                        + " use ContentResolver.openFileDescriptor() instead");
+                    }
+                default:
+                    return super.getString(columnIndex);
+            }
         }
 
         private String getLocalUri() {
diff --git a/core/java/android/app/IActivityManager.java b/core/java/android/app/IActivityManager.java
index 61b1bc8..ceb14ad 100644
--- a/core/java/android/app/IActivityManager.java
+++ b/core/java/android/app/IActivityManager.java
@@ -92,7 +92,7 @@
             int userId) throws RemoteException;
     public boolean startNextMatchingActivity(IBinder callingActivity,
             Intent intent, Bundle options) throws RemoteException;
-    public int startActivityFromRecents(int taskId, int launchStackId, Bundle options)
+    public int startActivityFromRecents(int taskId, Bundle options)
             throws RemoteException;
     public boolean finishActivity(IBinder token, int code, Intent data, int finishTask)
             throws RemoteException;
@@ -122,6 +122,7 @@
             PersistableBundle persistentState, CharSequence description) throws RemoteException;
     public void activitySlept(IBinder token) throws RemoteException;
     public void activityDestroyed(IBinder token) throws RemoteException;
+    public void activityRelaunched(IBinder token) throws RemoteException;
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
             int[] verticalSizeConfigurations, int[] smallestWidthConfigurations)
             throws RemoteException;
@@ -145,7 +146,31 @@
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) throws RemoteException;
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) throws RemoteException;
-    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) throws RemoteException;
+    public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode)
+            throws RemoteException;
+
+    /**
+     * Resizes the docked stack, and all other stacks as the result of the dock stack bounds change.
+     *
+     * @param dockedBounds The bounds for the docked stack.
+     * @param tempDockedTaskBounds The temporary bounds for the tasks in the docked stack, which
+     *                             might be different from the stack bounds to allow more
+     *                             flexibility while resizing, or {@code null} if they should be the
+     *                             same as the stack bounds.
+     * @param tempDockedTaskInsetBounds The temporary bounds for the tasks to calculate the insets.
+     *                                  When resizing, we usually "freeze" the layout of a task. To
+     *                                  achieve that, we also need to "freeze" the insets, which
+     *                                  gets achieved by changing task bounds but not bounds used
+     *                                  to calculate the insets in this transient state
+     * @param tempOtherTaskBounds The temporary bounds for the tasks in all other stacks, or
+     *                            {@code null} if they should be the same as the stack bounds.
+     * @param tempOtherTaskInsetBounds Like {@code tempDockedTaskInsetBounds}, but for the other
+     *                                 stacks.
+     * @throws RemoteException
+     */
+    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) throws RemoteException;
     public void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;
     public List<StackInfo> getAllStackInfos() throws RemoteException;
     public StackInfo getStackInfo(int stackId) throws RemoteException;
@@ -920,6 +945,8 @@
     int IN_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 353;
     int KILL_PACKAGE_DEPENDENTS_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 354;
     int ENTER_PICTURE_IN_PICTURE_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 355;
-    int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
+    int ACTIVITY_RELAUNCHED_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 356;
     int GET_URI_PERMISSION_OWNER_FOR_ACTIVITY_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 357;
+    int RESIZE_DOCKED_STACK_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 358;
+    int SET_VR_MODE_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 359;
 }
diff --git a/core/java/android/app/INotificationManager.aidl b/core/java/android/app/INotificationManager.aidl
index abe9822..e60cb03 100644
--- a/core/java/android/app/INotificationManager.aidl
+++ b/core/java/android/app/INotificationManager.aidl
@@ -78,6 +78,8 @@
     void setOnNotificationPostedTrimFromListener(in INotificationListener token, int trim);
     void setInterruptionFilter(String pkg, int interruptionFilter);
 
+    void setImportanceFromAssistant(in INotificationListener token, String key, int importance, CharSequence explanation);
+
     ComponentName getEffectsSuppressor();
     boolean matchesCallFilter(in Bundle extras);
     boolean isSystemConditionProviderEnabled(String path);
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index 4b0935c..560e22a 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -18,5 +18,9 @@
 
 /** @hide */
 oneway interface ITaskStackListener {
+    /** Called whenever there are changes to the state of tasks in a stack. */
     void onTaskStackChanged();
+
+    /** Called whenever an Activity is moved to the pinned stack from another stack. */
+    void onActivityPinned();
 }
diff --git a/core/java/android/app/NotificationManager.java b/core/java/android/app/NotificationManager.java
index 85d9831..9a3c820 100644
--- a/core/java/android/app/NotificationManager.java
+++ b/core/java/android/app/NotificationManager.java
@@ -637,10 +637,12 @@
         public static final int SUPPRESSED_EFFECTS_UNSET = -1;
         public static final int SUPPRESSED_EFFECT_LIGHTS = 1 << 0;
         public static final int SUPPRESSED_EFFECT_PEEK = 1 << 1;
+        public static final int SUPPRESSED_EFFECT_SCREEN_ON = 1 << 2;
 
         private static final int[] ALL_SUPPRESSED_EFFECTS = {
                 SUPPRESSED_EFFECT_LIGHTS,
                 SUPPRESSED_EFFECT_PEEK,
+                SUPPRESSED_EFFECT_SCREEN_ON,
         };
 
         /**
@@ -750,6 +752,7 @@
             switch (effect) {
                 case SUPPRESSED_EFFECT_LIGHTS: return "SUPPRESSED_EFFECT_LIGHTS";
                 case SUPPRESSED_EFFECT_PEEK: return "SUPPRESSED_EFFECT_PEEK";
+                case SUPPRESSED_EFFECT_SCREEN_ON: return "SUPPRESSED_EFFECT_SCREEN_ON";
                 case SUPPRESSED_EFFECTS_UNSET: return "SUPPRESSED_EFFECTS_UNSET";
                 default: return "UNKNOWN_" + effect;
             }
diff --git a/core/java/android/app/SystemServiceRegistry.java b/core/java/android/app/SystemServiceRegistry.java
index 288a2cb..89d52f2 100644
--- a/core/java/android/app/SystemServiceRegistry.java
+++ b/core/java/android/app/SystemServiceRegistry.java
@@ -247,7 +247,7 @@
                 new CachedServiceFetcher<DownloadManager>() {
             @Override
             public DownloadManager createService(ContextImpl ctx) {
-                return new DownloadManager(ctx.getContentResolver(), ctx.getPackageName());
+                return new DownloadManager(ctx);
             }});
 
         registerService(Context.BATTERY_SERVICE, BatteryManager.class,
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index eda0982..f940bd6 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -4802,4 +4802,129 @@
             Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, re);
         }
     }
+
+    /**
+     * Called by a device admin to set the short support message. This will
+     * be displayed to the user in settings screens where funtionality has
+     * been disabled by the admin.
+     *
+     * The message should be limited to a short statement such as
+     * "This setting is disabled by your administrator. Contact someone@example.com
+     *  for support."
+     * If the message is longer than 200 characters it may be truncated.
+     *
+     * @see #setLongSupportMessage
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param message Short message to be displayed to the user in settings or null to
+     *        clear the existing message.
+     */
+    public void setShortSupportMessage(@NonNull ComponentName admin,
+            @Nullable String message) {
+        if (mService != null) {
+            try {
+                mService.setShortSupportMessage(admin, message);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public String getShortSupportMessage(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getShortSupportMessage(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Called by a device admin to set the long support message. This will
+     * be displayed to the user in the device administators settings screen.
+     *
+     * @see #setShortSupportMessage
+     *
+     * @param admin Which {@link DeviceAdminReceiver} this request is associated with.
+     * @param message Long message to be displayed to the user in settings or null to
+     *        clear the existing message.
+     */
+    public void setLongSupportMessage(@NonNull ComponentName admin,
+            @Nullable String message) {
+        if (mService != null) {
+            try {
+                mService.setLongSupportMessage(admin, message);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+    }
+
+    /**
+     * 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.
+     */
+    public String getLongSupportMessage(@NonNull ComponentName admin) {
+        if (mService != null) {
+            try {
+                return mService.getLongSupportMessage(admin);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Called by the system to get the short support message.
+     *
+     * @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)}
+     *
+     * @hide
+     */
+    public String getShortSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getShortSupportMessageForUser(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * Called by the system to get the long support message.
+     *
+     * @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)}
+     *
+     * @hide
+     */
+    public String getLongSupportMessageForUser(@NonNull ComponentName admin, int userHandle) {
+        if (mService != null) {
+            try {
+                return mService.getLongSupportMessageForUser(admin, userHandle);
+            } catch (RemoteException e) {
+                Log.w(TAG, REMOTE_EXCEPTION_MESSAGE, e);
+            }
+        }
+        return null;
+    }
 }
diff --git a/core/java/android/app/admin/IDevicePolicyManager.aidl b/core/java/android/app/admin/IDevicePolicyManager.aidl
index 30ce682..f480a02 100644
--- a/core/java/android/app/admin/IDevicePolicyManager.aidl
+++ b/core/java/android/app/admin/IDevicePolicyManager.aidl
@@ -245,4 +245,12 @@
     boolean isSystemOnlyUser(in ComponentName admin);
     String getWifiMacAddress();
     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);
+
+    String getShortSupportMessageForUser(in ComponentName admin, int userHandle);
+    String getLongSupportMessageForUser(in ComponentName admin, int userHandle);
 }
diff --git a/core/java/android/content/ContentProviderClient.java b/core/java/android/content/ContentProviderClient.java
index d12595f..dec0d91 100644
--- a/core/java/android/content/ContentProviderClient.java
+++ b/core/java/android/content/ContentProviderClient.java
@@ -19,6 +19,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.AssetFileDescriptor;
+import android.database.CrossProcessCursorWrapper;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Bundle;
@@ -32,27 +33,34 @@
 import android.util.Log;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.Preconditions;
 
 import dalvik.system.CloseGuard;
 
 import java.io.FileNotFoundException;
 import java.util.ArrayList;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
- * The public interface object used to interact with a {@link ContentProvider}. This is obtained by
- * calling {@link ContentResolver#acquireContentProviderClient}. This object must be released
- * using {@link #release} in order to indicate to the system that the {@link ContentProvider} is
- * no longer needed and can be killed to free up resources.
- *
- * <p>Note that you should generally create a new ContentProviderClient instance
- * for each thread that will be performing operations.  Unlike
+ * The public interface object used to interact with a specific
+ * {@link ContentProvider}.
+ * <p>
+ * Instances can be obtained by calling
+ * {@link ContentResolver#acquireContentProviderClient} or
+ * {@link ContentResolver#acquireUnstableContentProviderClient}. Instances must
+ * be released using {@link #close()} in order to indicate to the system that
+ * the underlying {@link ContentProvider} is no longer needed and can be killed
+ * to free up resources.
+ * <p>
+ * Note that you should generally create a new ContentProviderClient instance
+ * for each thread that will be performing operations. Unlike
  * {@link ContentResolver}, the methods here such as {@link #query} and
- * {@link #openFile} are not thread safe -- you must not call
- * {@link #release()} on the ContentProviderClient those calls are made from
- * until you are finished with the data they have returned.
+ * {@link #openFile} are not thread safe -- you must not call {@link #close()}
+ * on the ContentProviderClient those calls are made from until you are finished
+ * with the data they have returned.
  */
-public class ContentProviderClient {
+public class ContentProviderClient implements AutoCloseable {
     private static final String TAG = "ContentProviderClient";
 
     @GuardedBy("ContentProviderClient.class")
@@ -63,22 +71,23 @@
     private final String mPackageName;
     private final boolean mStable;
 
-    private final CloseGuard mGuard = CloseGuard.get();
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
 
     private long mAnrTimeout;
     private NotRespondingRunnable mAnrRunnable;
 
-    private boolean mReleased;
-
     /** {@hide} */
-    ContentProviderClient(
+    @VisibleForTesting
+    public ContentProviderClient(
             ContentResolver contentResolver, IContentProvider contentProvider, boolean stable) {
         mContentResolver = contentResolver;
         mContentProvider = contentProvider;
         mPackageName = contentResolver.mPackageName;
+
         mStable = stable;
 
-        mGuard.open("release");
+        mCloseGuard.open("close");
     }
 
     /** {@hide} */
@@ -133,8 +142,9 @@
                 remoteCancellationSignal = mContentProvider.createCancellationSignal();
                 cancellationSignal.setRemote(remoteCancellationSignal);
             }
-            return mContentProvider.query(mPackageName, url, projection, selection, selectionArgs,
-                    sortOrder, remoteCancellationSignal);
+            final Cursor cursor = mContentProvider.query(mPackageName, url, projection, selection,
+                    selectionArgs, sortOrder, remoteCancellationSignal);
+            return new CursorWrapperInner(cursor);
         } catch (DeadObjectException e) {
             if (!mStable) {
                 mContentResolver.unstableProviderDied(mContentProvider);
@@ -446,29 +456,42 @@
     }
 
     /**
-     * Call this to indicate to the system that the associated {@link ContentProvider} is no
-     * longer needed by this {@link ContentProviderClient}.
-     * @return true if this was release, false if it was already released
+     * Closes this client connection, indicating to the system that the
+     * underlying {@link ContentProvider} is no longer needed.
      */
+    @Override
+    public void close() {
+        closeInternal();
+    }
+
+    /**
+     * @deprecated replaced by {@link #close()}.
+     */
+    @Deprecated
     public boolean release() {
-        synchronized (this) {
-            if (mReleased) {
-                throw new IllegalStateException("Already released");
-            }
-            mReleased = true;
-            mGuard.close();
+        return closeInternal();
+    }
+
+    private boolean closeInternal() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
             if (mStable) {
                 return mContentResolver.releaseProvider(mContentProvider);
             } else {
                 return mContentResolver.releaseUnstableProvider(mContentProvider);
             }
+        } else {
+            return false;
         }
     }
 
     @Override
     protected void finalize() throws Throwable {
-        if (mGuard != null) {
-            mGuard.warnIfOpen();
+        try {
+            mCloseGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
         }
     }
 
@@ -502,4 +525,29 @@
             mContentResolver.appNotRespondingViaProvider(mContentProvider);
         }
     }
+
+    private final class CursorWrapperInner extends CrossProcessCursorWrapper {
+        private final CloseGuard mCloseGuard = CloseGuard.get();
+
+        CursorWrapperInner(Cursor cursor) {
+            super(cursor);
+            mCloseGuard.open("close");
+        }
+
+        @Override
+        public void close() {
+            mCloseGuard.close();
+            super.close();
+        }
+
+        @Override
+        protected void finalize() throws Throwable {
+            try {
+                mCloseGuard.warnIfOpen();
+                close();
+            } finally {
+                super.finalize();
+            }
+        }
+    }
 }
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index 9d0ebc2..ce5d3b1 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -47,11 +47,11 @@
 import android.util.EventLog;
 import android.util.Log;
 
-import dalvik.system.CloseGuard;
-
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Preconditions;
 
+import dalvik.system.CloseGuard;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
@@ -59,9 +59,9 @@
 import java.io.InputStream;
 import java.io.OutputStream;
 import java.util.ArrayList;
-import java.util.Collections;
 import java.util.List;
 import java.util.Random;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * This class provides applications access to the content model.
@@ -514,8 +514,9 @@
             maybeLogQueryToEventLog(durationMillis, uri, projection, selection, sortOrder);
 
             // Wrap the cursor object into CursorWrapperInner object.
-            CursorWrapperInner wrapper = new CursorWrapperInner(qCursor,
-                    stableProvider != null ? stableProvider : acquireProvider(uri));
+            final IContentProvider provider = (stableProvider != null) ? stableProvider
+                    : acquireProvider(uri);
+            final CursorWrapperInner wrapper = new CursorWrapperInner(qCursor, provider);
             stableProvider = null;
             qCursor = null;
             return wrapper;
@@ -2503,41 +2504,31 @@
 
     private final class CursorWrapperInner extends CrossProcessCursorWrapper {
         private final IContentProvider mContentProvider;
-        public static final String TAG="CursorWrapperInner";
+        private final AtomicBoolean mProviderReleased = new AtomicBoolean();
 
         private final CloseGuard mCloseGuard = CloseGuard.get();
-        private boolean mProviderReleased;
 
-        CursorWrapperInner(Cursor cursor, IContentProvider icp) {
+        CursorWrapperInner(Cursor cursor, IContentProvider contentProvider) {
             super(cursor);
-            mContentProvider = icp;
+            mContentProvider = contentProvider;
             mCloseGuard.open("close");
         }
 
         @Override
         public void close() {
+            mCloseGuard.close();
             super.close();
-            ContentResolver.this.releaseProvider(mContentProvider);
-            mProviderReleased = true;
 
-            if (mCloseGuard != null) {
-                mCloseGuard.close();
+            if (mProviderReleased.compareAndSet(false, true)) {
+                ContentResolver.this.releaseProvider(mContentProvider);
             }
         }
 
         @Override
         protected void finalize() throws Throwable {
             try {
-                if (mCloseGuard != null) {
-                    mCloseGuard.warnIfOpen();
-                }
-
-                if (!mProviderReleased && mContentProvider != null) {
-                    // Even though we are using CloseGuard, log this anyway so that
-                    // application developers always see the message in the log.
-                    Log.w(TAG, "Cursor finalized without prior close()");
-                    ContentResolver.this.releaseProvider(mContentProvider);
-                }
+                mCloseGuard.warnIfOpen();
+                close();
             } finally {
                 super.finalize();
             }
@@ -2546,7 +2537,7 @@
 
     private final class ParcelFileDescriptorInner extends ParcelFileDescriptor {
         private final IContentProvider mContentProvider;
-        private boolean mProviderReleased;
+        private final AtomicBoolean mProviderReleased = new AtomicBoolean();
 
         ParcelFileDescriptorInner(ParcelFileDescriptor pfd, IContentProvider icp) {
             super(pfd);
@@ -2555,9 +2546,8 @@
 
         @Override
         public void releaseResources() {
-            if (!mProviderReleased) {
+            if (mProviderReleased.compareAndSet(false, true)) {
                 ContentResolver.this.releaseProvider(mContentProvider);
-                mProviderReleased = true;
             }
         }
     }
@@ -2584,7 +2574,9 @@
 
     private static IContentService sContentService;
     private final Context mContext;
+
     final String mPackageName;
+
     private static final String TAG = "ContentResolver";
 
     /** @hide */
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index 0f3ca10..35cd2be 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -3604,6 +3604,15 @@
     public static final String EXTRA_USER_ID = "android.intent.extra.USER_ID";
 
     /**
+     * An int representing the task id to be retrieved. This is used when a launch from recents is
+     * intercepted by another action such as credentials confirmation to remember which task should
+     * be resumed when complete.
+     *
+     * @hide
+     */
+    public static final String EXTRA_TASK_ID = "android.intent.extra.TASK_ID";
+
+    /**
      * An Intent[] describing additional, alternate choices you would like shown with
      * {@link #ACTION_CHOOSER}.
      *
@@ -4169,11 +4178,18 @@
 
     /**
      * Internal flag used to indicate that a system component has done their
-     * homework and verified their encryption-aware behavior.
+     * homework and verified that they correctly handle packages and components
+     * that come and go over time. In particular:
+     * <ul>
+     * <li>Apps installed on external storage, which will appear to be
+     * uninstalled while the the device is ejected.
+     * <li>Apps with encryption unaware components, which will appear to not
+     * exist while the device is locked.
+     * </ul>
      *
      * @hide
      */
-    public static final int FLAG_DEBUG_ENCRYPTION_TRIAGED = 0x00000100;
+    public static final int FLAG_DEBUG_TRIAGED_MISSING = 0x00000100;
 
     /**
      * If set, the new activity is not kept in the history stack.  As soon as
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 326735e..dedf07f5 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -281,6 +281,29 @@
      * {@see android.app.Activity#setVrMode(boolean)}.
      */
     public static final int FLAG_ENABLE_VR_MODE = 0x8000;
+
+    /**
+     * Bit in {@link #flags} indicating if the activity is resizeable to any dimension.
+     * See {@link android.R.attr#resizeableActivity}.
+     * @hide
+     */
+    public static final int FLAG_RESIZEABLE = 0x10000;
+
+    /**
+     * Bit in {@link #flags} indicating if the activity is supports picture-in-picture form of
+     * multi-window mode. See {@link android.R.attr#supportsPictureInPicture}.
+     * @hide
+     */
+    public static final int FLAG_SUPPORTS_PICTURE_IN_PICTURE = 0x20000;
+
+    /**
+     * Bit in {@link #flags} indicating if the activity is always focusable regardless of if it is
+     * in a task/stack whose activities are normally not focusable.
+     * See android.R.attr#alwaysFocusable.
+     * @hide
+     */
+    public static final int FLAG_ALWAYS_FOCUSABLE = 0x40000;
+
     /**
      * @hide Bit in {@link #flags}: If set, this component will only be seen
      * by the system user.  Only works with broadcast receivers.  Set from the
@@ -670,20 +693,6 @@
      */
     public String parentActivityName;
 
-    /**
-     * Value indicating if the activity is resizeable to any dimension.
-     * See {@link android.R.attr#resizeableActivity}.
-     * @hide
-     */
-    public boolean resizeable;
-
-    /**
-     * Value indicating if the activity is supports picture-in-picture form of multi-window mode.
-     * See {@link android.R.attr#supportsPictureInPicture}.
-     * @hide
-     */
-    public boolean supportsPip;
-
     /** @hide */
     public static final int LOCK_TASK_LAUNCH_MODE_DEFAULT = 0;
     /** @hide */
@@ -735,8 +744,6 @@
         uiOptions = orig.uiOptions;
         parentActivityName = orig.parentActivityName;
         maxRecents = orig.maxRecents;
-        resizeable = orig.resizeable;
-        supportsPip = orig.supportsPip;
         lockTaskLaunchMode = orig.lockTaskLaunchMode;
         layout = orig.layout;
     }
@@ -791,7 +798,6 @@
             pw.println(prefix + " uiOptions=0x" + Integer.toHexString(uiOptions));
         }
         if ((flags&DUMP_FLAG_DETAILS) != 0) {
-            pw.println(prefix + "resizeable=" + resizeable + " supportsPip=" + supportsPip);
             pw.println(prefix + "lockTaskLaunchMode="
                     + lockTaskLaunchModeToString(lockTaskLaunchMode));
         }
@@ -829,8 +835,6 @@
         dest.writeString(parentActivityName);
         dest.writeInt(persistableMode);
         dest.writeInt(maxRecents);
-        dest.writeInt(resizeable ? 1 : 0);
-        dest.writeInt(supportsPip ? 1 : 0);
         dest.writeInt(lockTaskLaunchMode);
         if (layout != null) {
             dest.writeInt(1);
@@ -871,8 +875,6 @@
         parentActivityName = source.readString();
         persistableMode = source.readInt();
         maxRecents = source.readInt();
-        resizeable = (source.readInt() == 1);
-        supportsPip = (source.readInt() == 1);
         lockTaskLaunchMode = source.readInt();
         if (source.readInt() == 1) {
             layout = new Layout(source);
diff --git a/core/java/android/content/pm/ManifestDigest.java b/core/java/android/content/pm/ManifestDigest.java
deleted file mode 100644
index e7dc764..0000000
--- a/core/java/android/content/pm/ManifestDigest.java
+++ /dev/null
@@ -1,147 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import com.android.internal.util.HexDump;
-
-import android.annotation.SystemApi;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.util.Slog;
-
-import java.io.BufferedInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.DigestInputStream;
-import java.security.MessageDigest;
-import java.security.NoSuchAlgorithmException;
-import java.util.Arrays;
-
-import libcore.io.IoUtils;
-
-/**
- * Represents the manifest digest for a package. This is suitable for comparison
- * of two packages to know whether the manifests are identical.
- *
- * @hide
- */
-@SystemApi
-public class ManifestDigest implements Parcelable {
-    private static final String TAG = "ManifestDigest";
-
-    /** The digest of the manifest in our preferred order. */
-    private final byte[] mDigest;
-
-    /** What we print out first when toString() is called. */
-    private static final String TO_STRING_PREFIX = "ManifestDigest {mDigest=";
-
-    /** Digest algorithm to use. */
-    private static final String DIGEST_ALGORITHM = "SHA-256";
-
-    ManifestDigest(byte[] digest) {
-        mDigest = digest;
-    }
-
-    private ManifestDigest(Parcel source) {
-        mDigest = source.createByteArray();
-    }
-
-    static ManifestDigest fromInputStream(InputStream fileIs) {
-        if (fileIs == null) {
-            return null;
-        }
-
-        final MessageDigest md;
-        try {
-            md = MessageDigest.getInstance(DIGEST_ALGORITHM);
-        } catch (NoSuchAlgorithmException e) {
-            throw new RuntimeException(DIGEST_ALGORITHM + " must be available", e);
-        }
-
-        final DigestInputStream dis = new DigestInputStream(new BufferedInputStream(fileIs), md);
-        try {
-            byte[] readBuffer = new byte[8192];
-            while (dis.read(readBuffer, 0, readBuffer.length) != -1) {
-                // not using
-            }
-        } catch (IOException e) {
-            Slog.w(TAG, "Could not read manifest");
-            return null;
-        } finally {
-            IoUtils.closeQuietly(dis);
-        }
-
-        final byte[] digest = md.digest();
-        return new ManifestDigest(digest);
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public boolean equals(Object o) {
-        if (!(o instanceof ManifestDigest)) {
-            return false;
-        }
-
-        final ManifestDigest other = (ManifestDigest) o;
-
-        return this == other || Arrays.equals(mDigest, other.mDigest);
-    }
-
-    @Override
-    public int hashCode() {
-        return Arrays.hashCode(mDigest);
-    }
-
-    @Override
-    public String toString() {
-        final StringBuilder sb = new StringBuilder(TO_STRING_PREFIX.length()
-                + (mDigest.length * 3) + 1);
-
-        sb.append(TO_STRING_PREFIX);
-
-        final int N = mDigest.length;
-        for (int i = 0; i < N; i++) {
-            final byte b = mDigest[i];
-            HexDump.appendByteAsHex(sb, b, false);
-            sb.append(',');
-        }
-        sb.append('}');
-
-        return sb.toString();
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeByteArray(mDigest);
-    }
-
-    public static final Parcelable.Creator<ManifestDigest> CREATOR
-            = new Parcelable.Creator<ManifestDigest>() {
-        public ManifestDigest createFromParcel(Parcel source) {
-            return new ManifestDigest(source);
-        }
-
-        public ManifestDigest[] newArray(int size) {
-            return new ManifestDigest[size];
-        }
-    };
-
-}
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index 69f508e..a38a9d7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -93,6 +93,109 @@
     }
 
     /**
+     * As a guiding principle:
+     * <p>
+     * {@code GET_} flags are used to request additional data that may have been
+     * elided to save wire space.
+     * <p>
+     * {@code MATCH_} flags are used to include components or packages that
+     * would have otherwise been omitted from a result set by current system
+     * state.
+     */
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_ACTIVITIES,
+            GET_RECEIVERS,
+            GET_SERVICES,
+            GET_PROVIDERS,
+            GET_INSTRUMENTATION,
+            GET_INTENT_FILTERS,
+            GET_SIGNATURES,
+            GET_META_DATA,
+            GET_GIDS,
+            GET_SHARED_LIBRARY_FILES,
+            GET_URI_PERMISSION_PATTERNS,
+            GET_PERMISSIONS,
+            GET_CONFIGURATIONS,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PackageInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ApplicationInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_ALL,
+            MATCH_DEFAULT_ONLY,
+            MATCH_ENCRYPTION_AWARE,
+            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ComponentInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+            GET_SHARED_LIBRARY_FILES,
+            GET_RESOLVED_FILTER,
+            MATCH_UNINSTALLED_PACKAGES,
+            MATCH_DISABLED_COMPONENTS,
+            MATCH_DISABLED_UNTIL_USED_COMPONENTS,
+            MATCH_ALL,
+            MATCH_DEFAULT_ONLY,
+            MATCH_ENCRYPTION_AWARE,
+            MATCH_ENCRYPTION_AWARE_AND_UNAWARE,
+            MATCH_ENCRYPTION_UNAWARE,
+            MATCH_SYSTEM_ONLY,
+            MATCH_DEBUG_TRIAGED_MISSING,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface ResolveInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface PermissionGroupInfoFlags {}
+
+    /** @hide */
+    @IntDef(flag = true, value = {
+            GET_META_DATA,
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface InstrumentationInfoFlags {}
+
+    /**
      * {@link PackageInfo} flag: return information about
      * activities in the package in {@link PackageInfo#activities}.
      */
@@ -161,9 +264,15 @@
     public static final int GET_GIDS                    = 0x00000100;
 
     /**
+     * @deprecated replaced with {@link #MATCH_DISABLED_COMPONENTS}
+     */
+    @Deprecated
+    public static final int GET_DISABLED_COMPONENTS = 0x00000200;
+
+    /**
      * {@link PackageInfo} flag: include disabled components in the returned info.
      */
-    public static final int GET_DISABLED_COMPONENTS     = 0x00000200;
+    public static final int MATCH_DISABLED_COMPONENTS = 0x00000200;
 
     /**
      * {@link ApplicationInfo} flag: return the
@@ -190,6 +299,12 @@
     public static final int GET_PERMISSIONS               = 0x00001000;
 
     /**
+     * @deprecated replaced with {@link #MATCH_UNINSTALLED_PACKAGES}
+     */
+    @Deprecated
+    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+
+    /**
      * Flag parameter to retrieve some information about all applications (even
      * uninstalled ones) which have data directories. This state could have
      * resulted if applications have been deleted with flag
@@ -199,7 +314,7 @@
      * Note: this flag may cause less information about currently installed
      * applications to be returned.
      */
-    public static final int GET_UNINSTALLED_PACKAGES = 0x00002000;
+    public static final int MATCH_UNINSTALLED_PACKAGES = 0x00002000;
 
     /**
      * {@link PackageInfo} flag: return information about
@@ -211,12 +326,18 @@
     public static final int GET_CONFIGURATIONS = 0x00004000;
 
     /**
+     * @deprecated replaced with {@link #MATCH_DISABLED_UNTIL_USED_COMPONENTS}.
+     */
+    @Deprecated
+    public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+
+    /**
      * {@link PackageInfo} flag: include disabled components which are in
      * that state only because of {@link #COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED}
      * in the returned info.  Note that if you set this flag, applications
      * that are in this disabled state will be reported as enabled.
      */
-    public static final int GET_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
+    public static final int MATCH_DISABLED_UNTIL_USED_COMPONENTS = 0x00008000;
 
     /**
      * Resolution and querying flag: if set, only filters that support the
@@ -227,48 +348,55 @@
     public static final int MATCH_DEFAULT_ONLY  = 0x00010000;
 
     /**
-     * Querying flag: if set and if the platform is doing any filtering of the results, then
-     * the filtering will not happen. This is a synonym for saying that all results should
-     * be returned.
+     * Querying flag: if set and if the platform is doing any filtering of the
+     * results, then the filtering will not happen. This is a synonym for saying
+     * that all results should be returned.
+     * <p>
+     * <em>This flag should be used with extreme care.</em>
      */
     public static final int MATCH_ALL = 0x00020000;
 
     /**
-     * {@link PackageInfo} flag: include only components which are encryption
-     * unaware in the returned info, regardless of the current user state.
+     * Querying flag: include only components which are encryption unaware in
+     * the returned info, regardless of the current user state.
      */
-    public static final int MATCH_ENCRYPTION_UNAWARE_ONLY = 0x00040000;
+    public static final int MATCH_ENCRYPTION_UNAWARE = 0x00040000;
 
     /**
-     * {@link PackageInfo} flag: include only components which are encryption
-     * aware in the returned info, regardless of the current user state.
+     * Querying flag: include only components which are encryption aware in the
+     * returned info, regardless of the current user state.
      */
-    public static final int MATCH_ENCRYPTION_AWARE_ONLY = 0x00080000;
+    public static final int MATCH_ENCRYPTION_AWARE = 0x00080000;
 
     /**
-     * {@link PackageInfo} flag: include both encryption aware and unaware
-     * components in the returned info, regardless of the current user state.
+     * Querying flag: include both encryption aware and unaware components in
+     * the returned info, regardless of the current user state.
      */
-    public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE_ONLY
-            | MATCH_ENCRYPTION_UNAWARE_ONLY;
+    public static final int MATCH_ENCRYPTION_AWARE_AND_UNAWARE = MATCH_ENCRYPTION_AWARE
+            | MATCH_ENCRYPTION_UNAWARE;
 
     /**
-     * {@link PackageInfo} flag: include only components from applications that
-     * are marked with {@link ApplicationInfo#FLAG_SYSTEM}.
-     *
-     * @hide
+     * Querying flag: include only components from applications that are marked
+     * with {@link ApplicationInfo#FLAG_SYSTEM}.
      */
     public static final int MATCH_SYSTEM_ONLY = 0x00100000;
 
     /**
-     * {@link PackageInfo} flag: use the default encryption matching behavior
-     * based on user state. Internal flag used to indicate that a system
-     * component has done their homework and verified their encryption-aware
-     * behavior.
+     * Internal flag used to indicate that a system component has done their
+     * homework and verified that they correctly handle packages and components
+     * that come and go over time. In particular:
+     * <ul>
+     * <li>Apps installed on external storage, which will appear to be
+     * uninstalled while the the device is ejected.
+     * <li>Apps with encryption unaware components, which will appear to not
+     * exist while the device is locked.
+     * </ul>
      *
+     * @see #MATCH_UNINSTALLED_PACKAGES
+     * @see #MATCH_ENCRYPTION_AWARE_AND_UNAWARE
      * @hide
      */
-    public static final int MATCH_ENCRYPTION_DEFAULT = 0x10000000;
+    public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
 
     /**
      * Flag for {@link addCrossProfileIntentFilter}: if this flag is set:
@@ -1819,7 +1947,6 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: This device supports ethernet.
-     * @hide
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_ETHERNET = "android.hardware.ethernet";
@@ -2131,7 +2258,7 @@
      * @see #GET_SIGNATURES
      * @see #GET_UNINSTALLED_PACKAGES
      */
-    public abstract PackageInfo getPackageInfo(String packageName, int flags)
+    public abstract PackageInfo getPackageInfo(String packageName, @PackageInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -2171,8 +2298,8 @@
      * @see #GET_UNINSTALLED_PACKAGES
      */
     @RequiresPermission(Manifest.permission.INTERACT_ACROSS_USERS)
-    public abstract PackageInfo getPackageInfoAsUser(String packageName, int flags, int userId)
-            throws NameNotFoundException;
+    public abstract PackageInfo getPackageInfoAsUser(String packageName,
+            @PackageInfoFlags int flags, int userId) throws NameNotFoundException;
 
     /**
      * Map from the current package names in use on the device to whatever
@@ -2270,7 +2397,7 @@
      * @return Returns a {@link PermissionInfo} containing information about the
      *         permission.
      */
-    public abstract PermissionInfo getPermissionInfo(String name, int flags)
+    public abstract PermissionInfo getPermissionInfo(String name, @PermissionInfoFlags int flags)
             throws NameNotFoundException;
 
     /**
@@ -2289,7 +2416,7 @@
      * about all of the permissions in the given group.
      */
     public abstract List<PermissionInfo> queryPermissionsByGroup(String group,
-            int flags) throws NameNotFoundException;
+            @PermissionInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular group of
@@ -2307,7 +2434,7 @@
      * about the permission.
      */
     public abstract PermissionGroupInfo getPermissionGroupInfo(String name,
-            int flags) throws NameNotFoundException;
+            @PermissionGroupInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the known permission groups in the system.
@@ -2318,7 +2445,8 @@
      * @return Returns a list of {@link PermissionGroupInfo} containing
      * information about all of the known permission groups.
      */
-    public abstract List<PermissionGroupInfo> getAllPermissionGroups(int flags);
+    public abstract List<PermissionGroupInfo> getAllPermissionGroups(
+            @PermissionGroupInfoFlags int flags);
 
     /**
      * Retrieve all of the information we know about a particular
@@ -2348,7 +2476,7 @@
      * @see #GET_UNINSTALLED_PACKAGES
      */
     public abstract ApplicationInfo getApplicationInfo(String packageName,
-            int flags) throws NameNotFoundException;
+            @ApplicationInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular activity
@@ -2371,7 +2499,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ActivityInfo getActivityInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular receiver
@@ -2394,7 +2522,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ActivityInfo getReceiverInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular service
@@ -2416,7 +2544,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ServiceInfo getServiceInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve all of the information we know about a particular content
@@ -2438,7 +2566,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      */
     public abstract ProviderInfo getProviderInfo(ComponentName component,
-            int flags) throws NameNotFoundException;
+            @ComponentInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Return a List of all packages that are installed
@@ -2474,7 +2602,7 @@
      * @see #GET_SIGNATURES
      * @see #GET_UNINSTALLED_PACKAGES
      */
-    public abstract List<PackageInfo> getInstalledPackages(int flags);
+    public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags);
 
     /**
      * Return a List of all installed packages that are currently
@@ -2507,7 +2635,7 @@
      * @see #GET_UNINSTALLED_PACKAGES
      */
     public abstract List<PackageInfo> getPackagesHoldingPermissions(
-            String[] permissions, int flags);
+            String[] permissions, @PackageInfoFlags int flags);
 
     /**
      * Return a List of all packages that are installed on the device, for a specific user.
@@ -2546,7 +2674,7 @@
      *
      * @hide
      */
-    public abstract List<PackageInfo> getInstalledPackages(int flags, int userId);
+    public abstract List<PackageInfo> getInstalledPackages(@PackageInfoFlags int flags, int userId);
 
     /**
      * Check whether a particular package has been granted a particular
@@ -2886,7 +3014,7 @@
      * @see #GET_SHARED_LIBRARY_FILES
      * @see #GET_UNINSTALLED_PACKAGES
      */
-    public abstract List<ApplicationInfo> getInstalledApplications(int flags);
+    public abstract List<ApplicationInfo> getInstalledApplications(@ApplicationInfoFlags int flags);
 
     /**
      * Gets the ephemeral applications the user recently used. Requires
@@ -3021,7 +3149,7 @@
      * @see #GET_INTENT_FILTERS
      * @see #GET_RESOLVED_FILTER
      */
-    public abstract ResolveInfo resolveActivity(Intent intent, int flags);
+    public abstract ResolveInfo resolveActivity(Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Determine the best action to perform for a given Intent for a given user. This
@@ -3054,7 +3182,8 @@
      *
      * @hide
      */
-    public abstract ResolveInfo resolveActivityAsUser(Intent intent, int flags, int userId);
+    public abstract ResolveInfo resolveActivityAsUser(Intent intent, @ResolveInfoFlags int flags,
+            int userId);
 
     /**
      * Retrieve all activities that can be performed for the given intent.
@@ -3077,7 +3206,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryIntentActivities(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all activities that can be performed for the given intent, for a specific user.
@@ -3101,8 +3230,7 @@
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentActivitiesAsUser(Intent intent,
-            int flags, int userId);
-
+            @ResolveInfoFlags int flags, int userId);
 
     /**
      * Retrieve a set of activities that should be presented to the user as
@@ -3134,7 +3262,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryIntentActivityOptions(
-            ComponentName caller, Intent[] specifics, Intent intent, int flags);
+            ComponentName caller, Intent[] specifics, Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all receivers that can handle a broadcast of the given intent.
@@ -3151,7 +3279,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all receivers that can handle a broadcast of the given intent, for a specific
@@ -3171,7 +3299,7 @@
      * @hide
      */
     public abstract List<ResolveInfo> queryBroadcastReceivers(Intent intent,
-            int flags, int userId);
+            @ResolveInfoFlags int flags, int userId);
 
     /**
      * Determine the best service to handle for a given Intent.
@@ -3187,7 +3315,7 @@
      * @see #GET_INTENT_FILTERS
      * @see #GET_RESOLVED_FILTER
      */
-    public abstract ResolveInfo resolveService(Intent intent, int flags);
+    public abstract ResolveInfo resolveService(Intent intent, @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all services that can match the given intent.
@@ -3205,7 +3333,7 @@
      * @see #GET_RESOLVED_FILTER
      */
     public abstract List<ResolveInfo> queryIntentServices(Intent intent,
-            int flags);
+            @ResolveInfoFlags int flags);
 
     /**
      * Retrieve all services that can match the given intent for a given user.
@@ -3226,11 +3354,11 @@
      * @hide
      */
     public abstract List<ResolveInfo> queryIntentServicesAsUser(Intent intent,
-            int flags, int userId);
+            @ResolveInfoFlags int flags, int userId);
 
     /** {@hide} */
     public abstract List<ResolveInfo> queryIntentContentProvidersAsUser(
-            Intent intent, int flags, int userId);
+            Intent intent, @ResolveInfoFlags int flags, int userId);
 
     /**
      * Retrieve all providers that can match the given intent.
@@ -3244,7 +3372,8 @@
      * @see #GET_INTENT_FILTERS
      * @see #GET_RESOLVED_FILTER
      */
-    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent, int flags);
+    public abstract List<ResolveInfo> queryIntentContentProviders(Intent intent,
+            @ResolveInfoFlags int flags);
 
     /**
      * Find a single content provider by its base path name.
@@ -3256,7 +3385,7 @@
      *         else null.
      */
     public abstract ProviderInfo resolveContentProvider(String name,
-            int flags);
+            @ComponentInfoFlags int flags);
 
     /**
      * Find a single content provider by its base path name.
@@ -3269,7 +3398,8 @@
      *         else null.
      * @hide
      */
-    public abstract ProviderInfo resolveContentProviderAsUser(String name, int flags, int userId);
+    public abstract ProviderInfo resolveContentProviderAsUser(String name,
+            @ComponentInfoFlags int flags, int userId);
 
     /**
      * Retrieve content provider information.
@@ -3290,7 +3420,7 @@
      *         <em>If there are no matching providers, null is returned.</em>
      */
     public abstract List<ProviderInfo> queryContentProviders(
-            String processName, int uid, int flags);
+            String processName, int uid, @ComponentInfoFlags int flags);
 
     /**
      * Retrieve all of the information we know about a particular
@@ -3307,8 +3437,8 @@
      * @return InstrumentationInfo containing information about the
      *         instrumentation.
      */
-    public abstract InstrumentationInfo getInstrumentationInfo(
-            ComponentName className, int flags) throws NameNotFoundException;
+    public abstract InstrumentationInfo getInstrumentationInfo(ComponentName className,
+            @InstrumentationInfoFlags int flags) throws NameNotFoundException;
 
     /**
      * Retrieve information about available instrumentation code.  May be used
@@ -3324,8 +3454,8 @@
      *         matching available Instrumentation.  Returns an empty list if
      *         there is no instrumentation available for the given package.
      */
-    public abstract List<InstrumentationInfo> queryInstrumentation(
-            String targetPackage, int flags);
+    public abstract List<InstrumentationInfo> queryInstrumentation(String targetPackage,
+            @InstrumentationInfoFlags int flags);
 
     /**
      * Retrieve an image from a package.  This is a low-level API used by
@@ -3761,14 +3891,13 @@
      * @see #GET_SIGNATURES
      *
      */
-    public PackageInfo getPackageArchiveInfo(String archiveFilePath, int flags) {
+    public PackageInfo getPackageArchiveInfo(String archiveFilePath, @PackageInfoFlags int flags) {
         final PackageParser parser = new PackageParser();
         final File apkFile = new File(archiveFilePath);
         try {
             PackageParser.Package pkg = parser.parseMonolithicPackage(apkFile, 0);
             if ((flags & GET_SIGNATURES) != 0) {
                 parser.collectCertificates(pkg, 0);
-                parser.collectManifestDigest(pkg);
             }
             PackageUserState state = new PackageUserState();
             return PackageParser.generatePackageInfo(pkg, null, flags, 0, 0, null, state);
@@ -3828,14 +3957,12 @@
      * @param verificationURI The location of the supplementary verification
      *            file. This can be a 'file:' or a 'content:' URI. May be
      *            {@code null}.
-     * @param manifestDigest an object that holds the digest of the package
-     *            which can be used to verify ownership. May be {@code null}.
      * @param encryptionParams if the package to be installed is encrypted,
      *            these parameters describing the encryption and authentication
      *            used. May be {@code null}.
      * @hide
      * @deprecated Use {@link #installPackageWithVerification(Uri,
-     *             PackageInstallObserver, int, String, Uri, ManifestDigest,
+     *             PackageInstallObserver, int, String, Uri,
      *             ContainerEncryptionParams)} instead. This method will
      *             continue to be supported but the older observer interface
      *             will not get additional failure details.
@@ -3843,7 +3970,7 @@
     // @SystemApi
     public abstract void installPackageWithVerification(Uri packageURI,
             IPackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
+            Uri verificationURI,
             ContainerEncryptionParams encryptionParams);
 
     /**
@@ -3952,8 +4079,6 @@
      * @param verificationURI The location of the supplementary verification
      *            file. This can be a 'file:' or a 'content:' URI. May be
      *            {@code null}.
-     * @param manifestDigest an object that holds the digest of the package
-     *            which can be used to verify ownership. May be {@code null}.
      * @param encryptionParams if the package to be installed is encrypted,
      *            these parameters describing the encryption and authentication
      *            used. May be {@code null}.
@@ -3961,7 +4086,7 @@
      */
     public abstract void installPackageWithVerification(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
+            Uri verificationURI,
             ContainerEncryptionParams encryptionParams);
 
     /**
@@ -4423,7 +4548,7 @@
      * @see #GET_SERVICES
      * @see #GET_SIGNATURES
      */
-    public abstract List<PackageInfo> getPreferredPackages(int flags);
+    public abstract List<PackageInfo> getPreferredPackages(@PackageInfoFlags int flags);
 
     /**
      * @deprecated This is a protected API that should not have been available
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index f445cf8..236cf64a 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -1032,31 +1032,6 @@
     }
 
     /**
-     * Gathers the {@link ManifestDigest} for {@code pkg} if it exists in the
-     * APK. If it successfully scanned the package and found the
-     * {@code AndroidManifest.xml}, {@code true} is returned.
-     */
-    public void collectManifestDigest(Package pkg) throws PackageParserException {
-        pkg.manifestDigest = null;
-
-        // TODO: extend to gather digest for split APKs
-        try {
-            final StrictJarFile jarFile = new StrictJarFile(pkg.baseCodePath);
-            try {
-                final ZipEntry je = jarFile.findEntry(ANDROID_MANIFEST_FILENAME);
-                if (je != null) {
-                    pkg.manifestDigest = ManifestDigest.fromInputStream(jarFile.getInputStream(je));
-                }
-            } finally {
-                jarFile.close();
-            }
-        } catch (IOException | RuntimeException e) {
-            throw new PackageParserException(INSTALL_PARSE_FAILED_MANIFEST_MALFORMED,
-                    "Failed to collect manifest digest");
-        }
-    }
-
-    /**
      * Collect certificates from all the APKs described in the given package,
      * populating {@link Package#mSignatures}. Also asserts that all APK
      * contents are signed correctly and consistently.
@@ -3223,12 +3198,19 @@
                 a.info.flags |= ActivityInfo.FLAG_RESUME_WHILE_PAUSING;
             }
 
-            a.info.resizeable = sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_resizeableActivity,
-                    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N);
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_resizeableActivity,
+                    owner.applicationInfo.targetSdkVersion >= Build.VERSION_CODES.N)) {
+                a.info.flags |= ActivityInfo.FLAG_RESIZEABLE;
 
-            a.info.supportsPip = a.info.resizeable ? sa.getBoolean(
-                    R.styleable.AndroidManifestActivity_supportsPictureInPicture, false) : false;
+                if (sa.getBoolean(R.styleable.AndroidManifestActivity_supportsPictureInPicture,
+                        false)) {
+                    a.info.flags |= ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
+                }
+            }
+
+            if (sa.getBoolean(R.styleable.AndroidManifestActivity_alwaysFocusable, false)) {
+                a.info.flags |= ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+            }
 
             a.info.screenOrientation = sa.getInt(
                     R.styleable.AndroidManifestActivity_screenOrientation,
@@ -4492,12 +4474,6 @@
         /* The required account type without which this application will not function */
         public String mRequiredAccountType;
 
-        /**
-         * Digest suitable for comparing whether this package's manifest is the
-         * same as another.
-         */
-        public ManifestDigest manifestDigest;
-
         public String mOverlayTarget;
         public int mOverlayPriority;
         public boolean mTrustedOverlay;
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index cfb4473..945858e6 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -24,6 +24,7 @@
 import android.util.Log;
 
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 /**
@@ -50,6 +51,10 @@
 
     private final List<T> mList;
 
+    public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
+        return new ParceledListSlice<T>(Collections.<T> emptyList());
+    }
+
     public ParceledListSlice(List<T> list) {
         mList = list;
     }
diff --git a/core/java/android/content/pm/VerificationParams.java b/core/java/android/content/pm/VerificationParams.java
index e5119b6..f90d295 100644
--- a/core/java/android/content/pm/VerificationParams.java
+++ b/core/java/android/content/pm/VerificationParams.java
@@ -16,7 +16,6 @@
 
 package android.content.pm;
 
-import android.content.pm.ManifestDigest;
 import android.net.Uri;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -51,12 +50,6 @@
     private int mInstallerUid;
 
     /**
-     * An object that holds the digest of the package which can be used to
-     * verify ownership.
-     */
-    private final ManifestDigest mManifestDigest;
-
-    /**
      * Creates verification specifications for installing with application verification.
      *
      * @param verificationURI The location of the supplementary verification
@@ -67,16 +60,13 @@
      *            May be {@code null}.
      * @param originatingUid UID of the application that the install request originated
      *            from, or NO_UID if not present
-     * @param manifestDigest an object that holds the digest of the package
-     *            which can be used to verify ownership. May be {@code null}.
      */
     public VerificationParams(Uri verificationURI, Uri originatingURI, Uri referrer,
-            int originatingUid, ManifestDigest manifestDigest) {
+            int originatingUid) {
         mVerificationURI = verificationURI;
         mOriginatingURI = originatingURI;
         mReferrer = referrer;
         mOriginatingUid = originatingUid;
-        mManifestDigest = manifestDigest;
         mInstallerUid = NO_UID;
     }
 
@@ -97,10 +87,6 @@
         return mOriginatingUid;
     }
 
-    public ManifestDigest getManifestDigest() {
-        return mManifestDigest;
-    }
-
     /** @return NO_UID when not set */
     public int getInstallerUid() {
         return mInstallerUid;
@@ -155,14 +141,6 @@
             return false;
         }
 
-        if (mManifestDigest == null) {
-            if (other.mManifestDigest != null) {
-                return false;
-            }
-        } else if (!mManifestDigest.equals(other.mManifestDigest)) {
-            return false;
-        }
-
         if (mInstallerUid != other.mInstallerUid) {
             return false;
         }
@@ -178,8 +156,7 @@
         hash += 7 * (mOriginatingURI == null ? 1 : mOriginatingURI.hashCode());
         hash += 11 * (mReferrer == null ? 1 : mReferrer.hashCode());
         hash += 13 * mOriginatingUid;
-        hash += 17 * (mManifestDigest == null ? 1 : mManifestDigest.hashCode());
-        hash += 19 * mInstallerUid;
+        hash += 17 * mInstallerUid;
 
         return hash;
     }
@@ -196,8 +173,6 @@
         sb.append(mReferrer.toString());
         sb.append(",mOriginatingUid=");
         sb.append(mOriginatingUid);
-        sb.append(",mManifestDigest=");
-        sb.append(mManifestDigest.toString());
         sb.append(",mInstallerUid=");
         sb.append(mInstallerUid);
         sb.append('}');
@@ -211,7 +186,6 @@
         dest.writeParcelable(mOriginatingURI, 0);
         dest.writeParcelable(mReferrer, 0);
         dest.writeInt(mOriginatingUid);
-        dest.writeParcelable(mManifestDigest, 0);
         dest.writeInt(mInstallerUid);
     }
 
@@ -221,7 +195,6 @@
         mOriginatingURI = source.readParcelable(Uri.class.getClassLoader());
         mReferrer = source.readParcelable(Uri.class.getClassLoader());
         mOriginatingUid = source.readInt();
-        mManifestDigest = source.readParcelable(ManifestDigest.class.getClassLoader());
         mInstallerUid = source.readInt();
     }
 
diff --git a/core/java/android/content/res/AssetManager.java b/core/java/android/content/res/AssetManager.java
index 7669053..ee6aec2 100644
--- a/core/java/android/content/res/AssetManager.java
+++ b/core/java/android/content/res/AssetManager.java
@@ -698,6 +698,18 @@
      */
     public native final String[] getLocales();
 
+    /**
+     * Same as getLocales(), except that locales that are only provided by the system (i.e. those
+     * present in framework-res.apk or its overlays) will not be listed.
+     *
+     * For example, if the "system" assets support English, French, and German, and the additional
+     * assets support Cherokee and French, getLocales() would return
+     * [Cherokee, English, French, German], while getNonSystemLocales() would return
+     * [Cherokee, French].
+     * {@hide}
+     */
+    public native final String[] getNonSystemLocales();
+
     /** {@hide} */
     public native final Configuration[] getSizeConfigurations();
 
diff --git a/core/java/android/content/res/Resources.java b/core/java/android/content/res/Resources.java
index 60c6e82..b01633e 100644
--- a/core/java/android/content/res/Resources.java
+++ b/core/java/android/content/res/Resources.java
@@ -1976,7 +1976,21 @@
 
             if (setLocalesToDefault || mResolvedLocale == null
                     || (configChanges & Configuration.NATIVE_CONFIG_LOCALE) != 0) {
-                mResolvedLocale = locales.getFirstMatch(mAssets.getLocales());
+                if (locales.size() == 1) {
+                    // This is an optimization to avoid the JNI call(s) when the result of
+                    // getFirstMatchWithEnglishSupported() does not depend on the supported locales.
+                    mResolvedLocale = locales.getPrimary();
+                } else {
+                    String[] supportedLocales = mAssets.getNonSystemLocales();
+                    if (LocaleList.isPseudoLocalesOnly(supportedLocales)) {
+                        // We fallback to all locales (including system locales) if there was no
+                        // locale specifically supported by the assets. This is to properly support
+                        // apps that only rely on the shared system assets and don't need assets of
+                        // their own.
+                        supportedLocales = mAssets.getLocales();
+                    }
+                    mResolvedLocale = locales.getFirstMatchWithEnglishSupported(supportedLocales);
+                }
             }
             mAssets.setConfiguration(mConfiguration.mcc, mConfiguration.mnc,
                     adjustLanguageTag(mResolvedLocale.toLanguageTag()),
diff --git a/core/java/android/provider/MediaStore.java b/core/java/android/provider/MediaStore.java
index 48b3c1a..89ac27c9a 100644
--- a/core/java/android/provider/MediaStore.java
+++ b/core/java/android/provider/MediaStore.java
@@ -384,8 +384,14 @@
 
     public interface MediaColumns extends BaseColumns {
         /**
-         * The data stream for the file
-         * <P>Type: DATA STREAM</P>
+         * Path to the file on disk.
+         * <p>
+         * Note that apps may not have filesystem permissions to directly access
+         * this path. Instead of trying to open this path directly, apps should
+         * use {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+         * access.
+         * <p>
+         * Type: TEXT
          */
         public static final String DATA = "_data";
 
@@ -1149,8 +1155,15 @@
             public static final String DEFAULT_SORT_ORDER = "image_id ASC";
 
             /**
-             * The data stream for the thumbnail
-             * <P>Type: DATA STREAM</P>
+             * Path to the thumbnail file on disk.
+             * <p>
+             * Note that apps may not have filesystem permissions to directly
+             * access this path. Instead of trying to open this path directly,
+             * apps should use
+             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+             * access.
+             * <p>
+             * Type: TEXT
              */
             public static final String DATA = "_data";
 
@@ -1596,8 +1609,15 @@
             public static final String NAME = "name";
 
             /**
-             * The data stream for the playlist file
-             * <P>Type: DATA STREAM</P>
+             * Path to the playlist file on disk.
+             * <p>
+             * Note that apps may not have filesystem permissions to directly
+             * access this path. Instead of trying to open this path directly,
+             * apps should use
+             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+             * access.
+             * <p>
+             * Type: TEXT
              */
             public static final String DATA = "_data";
 
@@ -2192,8 +2212,15 @@
             public static final String DEFAULT_SORT_ORDER = "video_id ASC";
 
             /**
-             * The data stream for the thumbnail
-             * <P>Type: DATA STREAM</P>
+             * Path to the thumbnail file on disk.
+             * <p>
+             * Note that apps may not have filesystem permissions to directly
+             * access this path. Instead of trying to open this path directly,
+             * apps should use
+             * {@link ContentResolver#openFileDescriptor(Uri, String)} to gain
+             * access.
+             * <p>
+             * Type: TEXT
              */
             public static final String DATA = "_data";
 
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index b883f9c..4eaee0b 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6374,6 +6374,13 @@
         public static final String DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES
                 = "force_resizable_activities";
 
+        /**
+         * Whether to enable experimental freeform support for windows.
+         * @hide
+         */
+        public static final String DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT
+                = "enable_freeform_support";
+
        /**
         * Whether user has enabled development settings.
         */
diff --git a/core/java/android/security/NetworkSecurityPolicy.java b/core/java/android/security/NetworkSecurityPolicy.java
index 46aa1af..37ec725 100644
--- a/core/java/android/security/NetworkSecurityPolicy.java
+++ b/core/java/android/security/NetworkSecurityPolicy.java
@@ -68,7 +68,6 @@
      * TLS or STARTTLS) is permitted for communicating with {@code hostname} for this process.
      *
      * @see #isCleartextTrafficPermitted()
-     * @hide
      */
     public boolean isCleartextTrafficPermitted(String hostname) {
         return libcore.net.NetworkSecurityPolicy.getInstance()
diff --git a/core/java/android/security/net/config/ApplicationConfig.java b/core/java/android/security/net/config/ApplicationConfig.java
index 71d9d5d..4de36cd 100644
--- a/core/java/android/security/net/config/ApplicationConfig.java
+++ b/core/java/android/security/net/config/ApplicationConfig.java
@@ -120,6 +120,32 @@
         return mTrustManager;
     }
 
+    /**
+     * Returns {@code true} if cleartext traffic is permitted for this application, which is the
+     * case only if all configurations permit cleartext traffic. For finer-grained policy use
+     * {@link #isCleartextTrafficPermitted(String)}.
+     */
+    public boolean isCleartextTrafficPermitted() {
+        ensureInitialized();
+        if (mConfigs != null) {
+            for (Pair<Domain, NetworkSecurityConfig> entry : mConfigs) {
+                if (!entry.second.isCleartextTrafficPermitted()) {
+                    return false;
+                }
+            }
+        }
+
+        return mDefaultConfig.isCleartextTrafficPermitted();
+    }
+
+    /**
+     * Returns {@code true} if cleartext traffic is permitted for this application when connecting
+     * to {@code hostname}.
+     */
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return getConfigForHostname(hostname).isCleartextTrafficPermitted();
+    }
+
     private void ensureInitialized() {
         synchronized(mLock) {
             if (mInitialized) {
diff --git a/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
new file mode 100644
index 0000000..e7d17c2
--- /dev/null
+++ b/core/java/android/security/net/config/ConfigNetworkSecurityPolicy.java
@@ -0,0 +1,40 @@
+/**
+ * Copyright (c) 2015, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.security.net.config;
+
+/**
+ * {@link libcore.net.NetworkSecurityPolicy} based on an {@link ApplicationConfig}.
+ *
+ * @hide
+ */
+public class ConfigNetworkSecurityPolicy extends libcore.net.NetworkSecurityPolicy {
+    private final ApplicationConfig mConfig;
+
+    public ConfigNetworkSecurityPolicy(ApplicationConfig config) {
+        mConfig = config;
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted() {
+        return mConfig.isCleartextTrafficPermitted();
+    }
+
+    @Override
+    public boolean isCleartextTrafficPermitted(String hostname) {
+        return mConfig.isCleartextTrafficPermitted(hostname);
+    }
+}
diff --git a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
index 5ebc7ac..0f66873 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfigProvider.java
@@ -40,5 +40,6 @@
             throw new RuntimeException("Failed to install provider as highest priority provider."
                     + " Provider was installed at position " + pos);
         }
+        libcore.net.NetworkSecurityPolicy.setInstance(new ConfigNetworkSecurityPolicy(config));
     }
 }
diff --git a/core/java/android/service/notification/INotificationAssistant.aidl b/core/java/android/service/notification/INotificationAssistant.aidl
deleted file mode 100644
index 5c5f358..0000000
--- a/core/java/android/service/notification/INotificationAssistant.aidl
+++ /dev/null
@@ -1,37 +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 android.service.notification;
-
-import android.service.notification.NotificationAdjustment;
-import android.service.notification.IStatusBarNotificationHolder;
-import android.service.notification.NotificationRankingUpdate;
-
-/** @hide */
-interface INotificationAssistant
-{
-    void onListenerConnected(in NotificationRankingUpdate update);
-    void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
-            in NotificationRankingUpdate update);
-    void onNotificationRankingUpdate(in NotificationRankingUpdate update);
-    void onListenerHintsChanged(int hints);
-    void onInterruptionFilterChanged(int interruptionFilter);
-    NotificationAdjustment onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
-    void onNotificationVisibilityChanged(String key, long time, boolean visible);
-    void onNotificationClick(String key, long time);
-    void onNotificationActionClick(String key, long time, int actionIndex);
-    void onNotificationRemoved(String key, long time, int reason);
-}
\ No newline at end of file
diff --git a/core/java/android/service/notification/INotificationListener.aidl b/core/java/android/service/notification/INotificationListener.aidl
index e6bf6ba..a0de17f 100644
--- a/core/java/android/service/notification/INotificationListener.aidl
+++ b/core/java/android/service/notification/INotificationListener.aidl
@@ -23,6 +23,7 @@
 /** @hide */
 oneway interface INotificationListener
 {
+    // listeners and assistants
     void onListenerConnected(in NotificationRankingUpdate update);
     void onNotificationPosted(in IStatusBarNotificationHolder notificationHolder,
             in NotificationRankingUpdate update);
@@ -31,4 +32,11 @@
     void onNotificationRankingUpdate(in NotificationRankingUpdate update);
     void onListenerHintsChanged(int hints);
     void onInterruptionFilterChanged(int interruptionFilter);
+
+    // assistants only
+    void onNotificationEnqueued(in IStatusBarNotificationHolder notificationHolder, int importance, boolean user);
+    void onNotificationVisibilityChanged(String key, long time, boolean visible);
+    void onNotificationClick(String key, long time);
+    void onNotificationActionClick(String key, long time, int actionIndex);
+    void onNotificationRemovedReason(String key, long time, int reason);
 }
diff --git a/core/java/android/service/notification/NotificationAdjustment.java b/core/java/android/service/notification/NotificationAdjustment.java
deleted file mode 100644
index c5f0db9..0000000
--- a/core/java/android/service/notification/NotificationAdjustment.java
+++ /dev/null
@@ -1,57 +0,0 @@
-package android.service.notification;
-
-import android.net.Uri;
-import android.os.Parcel;
-import android.os.Parcelable;
-
-public class NotificationAdjustment implements Parcelable {
-    int mImportance;
-    CharSequence mExplanation;
-    Uri mReference;
-
-    /**
-     * Create a notification importance adjustment.
-     *
-     * @param importance The final importance of the notification.
-     * @param explanation A human-readable justification for the adjustment.
-     * @param reference A reference to an external object that augments the
-     *                  explanation, such as a
-     *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
-     *                  or null.
-     */
-    public NotificationAdjustment(int importance, CharSequence explanation, Uri reference) {
-        mImportance = importance;
-        mExplanation = explanation;
-        mReference = reference;
-    }
-
-    private NotificationAdjustment(Parcel source) {
-        this(source.readInt(), source.readCharSequence(),
-                (Uri) source.readParcelable(NotificationAdjustment.class.getClassLoader()));
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mImportance);
-        dest.writeCharSequence(mExplanation);
-        dest.writeParcelable(mReference, 0);
-    }
-
-    public static final Parcelable.Creator<NotificationAdjustment> CREATOR
-            = new Parcelable.Creator<NotificationAdjustment>() {
-        @Override
-        public NotificationAdjustment createFromParcel(Parcel source) {
-            return new NotificationAdjustment(source);
-        }
-
-        @Override
-        public NotificationAdjustment[] newArray(int size) {
-            return new NotificationAdjustment[size];
-        }
-    };
-}
diff --git a/core/java/android/service/notification/NotificationAssistantService.java b/core/java/android/service/notification/NotificationAssistantService.java
index 7ce5e1f..3a8956e 100644
--- a/core/java/android/service/notification/NotificationAssistantService.java
+++ b/core/java/android/service/notification/NotificationAssistantService.java
@@ -20,8 +20,11 @@
 import android.app.Notification;
 import android.content.Intent;
 import android.net.Uri;
+import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
 
 /**
  * A service that helps the user manage notifications by modifying the
@@ -39,6 +42,8 @@
  * &lt;/service></pre>
  */
 public abstract class NotificationAssistantService extends NotificationListenerService {
+    private static final String TAG = "NotificationAssistant";
+
     /**
      * The {@link Intent} that must be declared as handled by the service.
      */
@@ -85,6 +90,36 @@
     /** Notification was canceled because it was an invisible member of a group. */
     public static final int REASON_GROUP_OPTIMIZATION = 13;
 
+    public class Adjustment {
+        int mImportance;
+        CharSequence mExplanation;
+        Uri mReference;
+
+        /**
+         * Create a notification importance adjustment.
+         *
+         * @param importance The final importance of the notification.
+         * @param explanation A human-readable justification for the adjustment.
+         * @param reference A reference to an external object that augments the
+         *                  explanation, such as a
+         *                  {@link android.provider.ContactsContract.Contacts#CONTENT_LOOKUP_URI},
+         *                  or null.
+         */
+        public Adjustment(int importance, CharSequence explanation, Uri reference) {
+            mImportance = importance;
+            mExplanation = explanation;
+            mReference = reference;
+        }
+    }
+
+    @Override
+    public IBinder onBind(Intent intent) {
+        if (mWrapper == null) {
+            mWrapper = new NotificationAssistantWrapper();
+        }
+        return mWrapper;
+    }
+
     /**
      * A notification was posted by an app. Called before alert.
      *
@@ -93,7 +128,7 @@
      * @param user true if the initial importance reflects an explicit user preference.
      * @return an adjustment or null to take no action, within 100ms.
      */
-    abstract public NotificationAdjustment onNotificationEnqueued(StatusBarNotification sbn,
+    abstract public Adjustment onNotificationEnqueued(StatusBarNotification sbn,
           int importance, boolean user);
 
     /**
@@ -150,9 +185,15 @@
      * @param key the notification key
      * @param adjustment the new importance with an explanation
      */
-    public final void adjustImportance(String key, NotificationAdjustment adjustment)
+    public final void adjustImportance(String key, Adjustment adjustment)
     {
-        // TODO: pack up the adjustment and send it to the NotificationManager.
+        if (!isBound()) return;
+        try {
+            getNotificationInterface().setImportanceFromAssistant(mWrapper, key,
+                    adjustment.mImportance, adjustment.mExplanation);
+        } catch (android.os.RemoteException ex) {
+            Log.v(TAG, "Unable to contact notification manager", ex);
+        }
     }
 
     /**
@@ -160,7 +201,7 @@
      * be fired when the host notification is deleted, or when this annotation
      * is removed or replaced.
      *
-     * @param key the notification key
+     * @param key the key of the notification to be annotated
      * @param annotation the new annotation object
      */
     public final void setAnnotation(String key, Notification annotation)
@@ -171,10 +212,74 @@
     /**
      * Remove the annotation from a notification.
      *
-     * @param key the notification key
+     * @param key the key of the notification to be cleansed of annotatons
      */
     public final void clearAnnotation(String key)
     {
         // TODO: ask the NotificationManager to clear the annotation.
     }
+
+    private class NotificationAssistantWrapper extends NotificationListenerWrapper {
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder sbnHolder,
+                                           int importance, boolean user) throws RemoteException {
+            StatusBarNotification sbn;
+            try {
+                sbn = sbnHolder.get();
+            } catch (RemoteException e) {
+                Log.w(TAG, "onNotificationEnqueued: Error receiving StatusBarNotification", e);
+                return;
+            }
+
+            try {
+                Adjustment adjustment =
+                    NotificationAssistantService.this.onNotificationEnqueued(sbn, importance, user);
+                if (adjustment != null) {
+                    adjustImportance(sbn.getKey(), adjustment);
+                }
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationEnqueued", t);
+            }
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+                throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationVisibilityChanged(key, time,
+                        visible);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationVisibilityChanged", t);
+            }
+        }
+
+        @Override
+        public void onNotificationClick(String key, long time) throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationClick(key, time);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationClick", t);
+            }
+        }
+
+        @Override
+        public void onNotificationActionClick(String key, long time, int actionIndex)
+                throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationActionClick(key, time, actionIndex);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationActionClick", t);
+            }
+        }
+
+        @Override
+        public void onNotificationRemovedReason(String key, long time, int reason)
+                throws RemoteException {
+            try {
+                NotificationAssistantService.this.onNotificationRemoved(key, time, reason);
+            } catch (Throwable t) {
+                Log.w(TAG, "Error running onNotificationRemoved", t);
+            }
+        }
+    }
 }
diff --git a/core/java/android/service/notification/NotificationListenerService.java b/core/java/android/service/notification/NotificationListenerService.java
index 1e62edc..b42d9ea 100644
--- a/core/java/android/service/notification/NotificationListenerService.java
+++ b/core/java/android/service/notification/NotificationListenerService.java
@@ -15,6 +15,7 @@
  */
 
 package android.service.notification;
+import android.service.notification.IStatusBarNotificationHolder;
 
 import android.annotation.SystemApi;
 import android.annotation.SdkConstant;
@@ -122,6 +123,8 @@
             NotificationManager.Policy.SUPPRESSED_EFFECT_LIGHTS;
     public static final int SUPPRESSED_EFFECT_PEEK =
             NotificationManager.Policy.SUPPRESSED_EFFECT_PEEK;
+    public static final int SUPPRESSED_EFFECT_SCREEN_ON =
+            NotificationManager.Policy.SUPPRESSED_EFFECT_SCREEN_ON;
 
     /**
      * The full trim of the StatusBarNotification including all its features.
@@ -151,7 +154,8 @@
     @SystemApi
     public static final int TRIM_LIGHT = 1;
 
-    private INotificationListenerWrapper mWrapper = null;
+    /** @hide */
+    protected NotificationListenerWrapper mWrapper = null;
     private RankingMap mRankingMap;
 
     private INotificationManager mNoMan;
@@ -291,7 +295,8 @@
         // optional
     }
 
-    private final INotificationManager getNotificationInterface() {
+    /** @hide */
+    protected final INotificationManager getNotificationInterface() {
         if (mNoMan == null) {
             mNoMan = INotificationManager.Stub.asInterface(
                     ServiceManager.getService(Context.NOTIFICATION_SERVICE));
@@ -634,12 +639,13 @@
     @Override
     public IBinder onBind(Intent intent) {
         if (mWrapper == null) {
-            mWrapper = new INotificationListenerWrapper();
+            mWrapper = new NotificationListenerWrapper();
         }
         return mWrapper;
     }
 
-    private boolean isBound() {
+    /** @hide */
+    protected boolean isBound() {
         if (mWrapper == null) {
             Log.w(TAG, "Notification listener service not yet bound.");
             return false;
@@ -664,7 +670,7 @@
             int currentUser) throws RemoteException {
         mSystemContext = context;
         if (mWrapper == null) {
-            mWrapper = new INotificationListenerWrapper();
+            mWrapper = new NotificationListenerWrapper();
         }
         INotificationManager noMan = getNotificationInterface();
         noMan.registerListener(mWrapper, componentName, currentUser);
@@ -716,7 +722,8 @@
         }
     }
 
-    private class INotificationListenerWrapper extends INotificationListener.Stub {
+    /** @hide */
+    protected class NotificationListenerWrapper extends INotificationListener.Stub {
         @Override
         public void onNotificationPosted(IStatusBarNotificationHolder sbnHolder,
                 NotificationRankingUpdate update) {
@@ -817,6 +824,35 @@
                 Log.w(TAG, "Error running onInterruptionFilterChanged", t);
             }
         }
+
+        @Override
+        public void onNotificationEnqueued(IStatusBarNotificationHolder notificationHolder,
+                                           int importance, boolean user) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationVisibilityChanged(String key, long time, boolean visible)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationClick(String key, long time) throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationActionClick(String key, long time, int actionIndex)
+                throws RemoteException {
+            // no-op in the listener
+        }
+
+        @Override
+        public void onNotificationRemovedReason(String key, long time, int reason)
+                throws RemoteException {
+            // no-op in the listener
+        }
     }
 
     private void applyUpdate(NotificationRankingUpdate update) {
@@ -927,7 +963,8 @@
 
         /**
          * Returns the type(s) of visual effects that should be suppressed for this notification.
-         * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK}}.
+         * See {@link #SUPPRESSED_EFFECT_LIGHTS}, {@link #SUPPRESSED_EFFECT_PEEK},
+         * {@link #SUPPRESSED_EFFECT_SCREEN_ON}.
          */
         public int getSuppressedVisualEffects() {
             return mSuppressedVisualEffects;
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 541623d..4688843 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -79,6 +79,7 @@
     private static final boolean DEFAULT_ALLOW_REPEAT_CALLERS = false;
     private static final boolean DEFAULT_ALLOW_PEEK = true;
     private static final boolean DEFAULT_ALLOW_LIGHTS = true;
+    private static final boolean DEFAULT_ALLOW_SCREEN_ON = true;
 
     private static final int XML_VERSION = 2;
     private static final String ZEN_TAG = "zen";
@@ -95,6 +96,7 @@
     private static final String ALLOW_ATT_EVENTS = "events";
     private static final String ALLOW_ATT_PEEK = "peek";
     private static final String ALLOW_ATT_LIGHTS = "lights";
+    private static final String ALLOW_ATT_SCREEN_ON = "screen_on";
 
     private static final String CONDITION_TAG = "condition";
     private static final String CONDITION_ATT_COMPONENT = "component";
@@ -128,6 +130,7 @@
     public int user = UserHandle.USER_SYSTEM;
     public boolean allowPeek = DEFAULT_ALLOW_PEEK;
     public boolean allowLights = DEFAULT_ALLOW_LIGHTS;
+    public boolean allowScreenOn = DEFAULT_ALLOW_SCREEN_ON;
 
     public ZenRule manualRule;
     public ArrayMap<String, ZenRule> automaticRules = new ArrayMap<>();
@@ -156,6 +159,7 @@
         }
         allowPeek = source.readInt() == 1;
         allowLights = source.readInt() == 1;
+        allowScreenOn = source.readInt() == 1;
     }
 
     @Override
@@ -185,6 +189,7 @@
         }
         dest.writeInt(allowPeek ? 1 : 0);
         dest.writeInt(allowLights ? 1 : 0);
+        dest.writeInt(allowScreenOn ? 1 : 0);
     }
 
     @Override
@@ -200,6 +205,7 @@
                 .append(",allowEvents=").append(allowEvents)
                 .append(",allowPeek=").append(allowPeek)
                 .append(",allowLights=").append(allowLights)
+                .append(",allowScreenOn=").append(allowScreenOn)
                 .append(",automaticRules=").append(automaticRules)
                 .append(",manualRule=").append(manualRule)
                 .append(']').toString();
@@ -240,6 +246,9 @@
         if (allowLights != to.allowLights) {
             d.addLine("allowLights", allowLights, to.allowLights);
         }
+        if (allowScreenOn != to.allowScreenOn) {
+            d.addLine("allowScreenOn", allowScreenOn, to.allowScreenOn);
+        }
         final ArraySet<String> allRules = new ArraySet<>();
         addKeys(allRules, automaticRules);
         addKeys(allRules, to.automaticRules);
@@ -339,6 +348,7 @@
                 && other.allowEvents == allowEvents
                 && other.allowPeek == allowPeek
                 && other.allowLights == allowLights
+                && other.allowScreenOn == allowScreenOn
                 && other.user == user
                 && Objects.equals(other.automaticRules, automaticRules)
                 && Objects.equals(other.manualRule, manualRule);
@@ -348,7 +358,7 @@
     public int hashCode() {
         return Objects.hash(allowCalls, allowRepeatCallers, allowMessages, allowCallsFrom,
                 allowMessagesFrom, allowReminders, allowEvents, allowPeek, allowLights,
-                user, automaticRules, manualRule);
+                allowScreenOn, user, automaticRules, manualRule);
     }
 
     private static String toDayList(int[] days) {
@@ -435,6 +445,8 @@
                     }
                     rt.allowPeek = safeBoolean(parser, ALLOW_ATT_PEEK, DEFAULT_ALLOW_PEEK);
                     rt.allowLights = safeBoolean(parser, ALLOW_ATT_LIGHTS, DEFAULT_ALLOW_LIGHTS);
+                    rt.allowScreenOn =
+                            safeBoolean(parser, ALLOW_ATT_SCREEN_ON, DEFAULT_ALLOW_SCREEN_ON);
                 } else if (MANUAL_TAG.equals(tag)) {
                     rt.manualRule = readRuleXml(parser);
                 } else if (AUTOMATIC_TAG.equals(tag)) {
@@ -465,6 +477,7 @@
         out.attribute(null, ALLOW_ATT_MESSAGES_FROM, Integer.toString(allowMessagesFrom));
         out.attribute(null, ALLOW_ATT_PEEK, Boolean.toString(allowPeek));
         out.attribute(null, ALLOW_ATT_LIGHTS, Boolean.toString(allowLights));
+        out.attribute(null, ALLOW_ATT_SCREEN_ON, Boolean.toString(allowScreenOn));
         out.endTag(null, ALLOW_TAG);
 
         if (manualRule != null) {
@@ -643,6 +656,9 @@
         if (!allowLights) {
             suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_LIGHTS;
         }
+        if (!allowScreenOn) {
+            suppressedVisualEffects |= Policy.SUPPRESSED_EFFECT_SCREEN_ON;
+        }
         priorityCallSenders = sourceToPrioritySenders(allowCallsFrom, priorityCallSenders);
         priorityMessageSenders = sourceToPrioritySenders(allowMessagesFrom, priorityMessageSenders);
         return new Policy(priorityCategories, priorityCallSenders, priorityMessageSenders,
@@ -681,6 +697,8 @@
         if (policy.suppressedVisualEffects != Policy.SUPPRESSED_EFFECTS_UNSET) {
             allowPeek = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_PEEK) == 0;
             allowLights = (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_LIGHTS) == 0;
+            allowScreenOn =
+                    (policy.suppressedVisualEffects & Policy.SUPPRESSED_EFFECT_SCREEN_ON) == 0;
         }
     }
 
diff --git a/core/java/android/service/quicksettings/IQSService.aidl b/core/java/android/service/quicksettings/IQSService.aidl
index 7e70501..75da82f 100644
--- a/core/java/android/service/quicksettings/IQSService.aidl
+++ b/core/java/android/service/quicksettings/IQSService.aidl
@@ -24,4 +24,5 @@
 interface IQSService {
     void updateQsTile(in Tile tile);
     void onShowDialog(in Tile tile);
+    void setTileMode(in ComponentName component, int mode);
 }
diff --git a/core/java/android/service/quicksettings/IQSTileService.aidl b/core/java/android/service/quicksettings/IQSTileService.aidl
index 63a4c5e..4997f75 100644
--- a/core/java/android/service/quicksettings/IQSTileService.aidl
+++ b/core/java/android/service/quicksettings/IQSTileService.aidl
@@ -22,6 +22,7 @@
  * @hide
  */
 oneway interface IQSTileService {
+    void setQSService(in IQSService service);
     void setQSTile(in Tile tile);
     void onTileAdded();
     void onTileRemoved();
diff --git a/core/java/android/service/quicksettings/Tile.java b/core/java/android/service/quicksettings/Tile.java
index a53fc59..6104913 100644
--- a/core/java/android/service/quicksettings/Tile.java
+++ b/core/java/android/service/quicksettings/Tile.java
@@ -37,11 +37,12 @@
     private static final String TAG = "Tile";
 
     private ComponentName mComponentName;
-    private IQSService mService;
     private Icon mIcon;
     private CharSequence mLabel;
     private CharSequence mContentDescription;
 
+    private IQSService mService;
+
     /**
      * @hide
      */
@@ -52,8 +53,14 @@
     /**
      * @hide
      */
-    public Tile(ComponentName componentName, IQSService service) {
+    public Tile(ComponentName componentName) {
         mComponentName = componentName;
+    }
+
+    /**
+     * @hide
+     */
+    public void setService(IQSService service) {
         mService = service;
     }
 
@@ -65,6 +72,13 @@
     }
 
     /**
+     * @hide
+     */
+    public IQSService getQsService() {
+        return mService;
+    }
+
+    /**
      * Gets the current icon for the tile.
      */
     public Icon getIcon() {
@@ -137,21 +151,8 @@
         }
     }
 
-    /**
-     * @hide
-     * Notifies the IQSService that this tile is showing a dialog.
-     */
-    void onShowDialog() {
-        try {
-            mService.onShowDialog(this);
-        } catch (RemoteException e) {
-            Log.e(TAG, "Couldn't onShowDialog");
-        }
-    }
-
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeStrongInterface(mService);
         if (mComponentName != null) {
             dest.writeByte((byte) 1);
             mComponentName.writeToParcel(dest, flags);
@@ -169,7 +170,6 @@
     }
 
     private void readFromParcel(Parcel source) {
-        mService = IQSService.Stub.asInterface(source.readStrongBinder());
         if (source.readByte() != 0) {
             mComponentName = ComponentName.CREATOR.createFromParcel(source);
         } else {
diff --git a/core/java/android/service/quicksettings/TileService.java b/core/java/android/service/quicksettings/TileService.java
index d8787b4..1e134c7 100644
--- a/core/java/android/service/quicksettings/TileService.java
+++ b/core/java/android/service/quicksettings/TileService.java
@@ -15,8 +15,11 @@
  */
 package android.service.quicksettings;
 
+import android.Manifest;
 import android.app.Dialog;
 import android.app.Service;
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.Intent;
 import android.os.Handler;
 import android.os.IBinder;
@@ -26,29 +29,29 @@
 import android.view.WindowManager;
 
 /**
- * A QSTileService provides the user a tile that can be added to Quick Settings.
+ * A TileService provides the user a tile that can be added to Quick Settings.
  * Quick Settings is a space provided that allows the user to change settings and
  * take quick actions without leaving the context of their current app.
  *
- * <p>The lifecycle of a QSTileService is different from some other services in
+ * <p>The lifecycle of a TileService is different from some other services in
  * that it may be unbound during parts of its lifecycle.  Any of the following
  * lifecycle events can happen indepently in a separate binding/creation of the
  * service.</p>
  *
  * <ul>
- * <li>When a tile is added by the user its QSTileService will be bound to and
+ * <li>When a tile is added by the user its TileService will be bound to and
  * {@link #onTileAdded()} will be called.</li>
  *
  * <li>When a tile should be up to date and listing will be indicated by
  * {@link #onStartListening()} and {@link #onStopListening()}.</li>
  *
- * <li>When the user removes a tile from Quick Settings {@link #onStopListening()}
+ * <li>When the user removes a tile from Quick Settings {@link #onTileRemoved()}
  * will be called.</li>
  * </ul>
- * <p>QSTileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
+ * <p>TileService will be detected by tiles that match the {@value #ACTION_QS_TILE}
  * and require the permission "android.permission.BIND_QUICK_SETTINGS_TILE".
  * The label and icon for the service will be used as the default label and
- * icon for the tile. Here is an example QSTileService declaration.</p>
+ * icon for the tile. Here is an example TileService declaration.</p>
  * <pre class="prettyprint">
  * {@literal
  * <service
@@ -67,15 +70,52 @@
 public class TileService extends Service {
 
     /**
-     * Action that identifies a Service as being a QSTileService.
+     * Action that identifies a Service as being a TileService.
      */
     public static final String ACTION_QS_TILE = "android.service.quicksettings.action.QS_TILE";
 
+    /**
+     * The tile mode hasn't been set yet.
+     * @hide
+     */
+    public static final int TILE_MODE_UNSET = 0;
+
+    /**
+     * Constant to be returned by {@link #onTileAdded}.
+     * <p>
+     * Passive mode is the default mode for tiles.  The System will tell the tile
+     * when it is most important to update by putting it in the listening state.
+     */
+    public static final int TILE_MODE_PASSIVE = 1;
+
+    /**
+     * Constant to be returned by {@link #onTileAdded}.
+     * <p>
+     * Active mode is for tiles which already listen and keep track of their state in their
+     * own process.  These tiles may request to send an update to the System while their process
+     * is alive using {@link #requestListeningState}.  The System will only bind these tiles
+     * on its own when a click needs to occur.
+     */
+    public static final int TILE_MODE_ACTIVE = 2;
+
+    /**
+     * Used to notify SysUI that Listening has be requested.
+     * @hide
+     */
+    public static final String ACTION_REQUEST_LISTENING
+            = "android.service.quicksettings.action.REQUEST_LISTENING";
+
+    /**
+     * @hide
+     */
+    public static final String EXTRA_COMPONENT = "android.service.quicksettings.extra.COMPONENT";
+
     private final H mHandler = new H(Looper.getMainLooper());
 
     private boolean mListening = false;
     private Tile mTile;
     private IBinder mToken;
+    private IQSService mService;
 
     @Override
     public void onDestroy() {
@@ -92,8 +132,12 @@
      * Note that this is not guaranteed to be called between {@link #onCreate()}
      * and {@link #onStartListening()}, it will only be called when the tile is added
      * and not on subsequent binds.
+     *
+     * @see #TILE_MODE_PASSIVE
+     * @see #TILE_MODE_ACTIVE
      */
-    public void onTileAdded() {
+    public int onTileAdded() {
+        return TILE_MODE_PASSIVE;
     }
 
     /**
@@ -138,7 +182,10 @@
         dialog.getWindow().getAttributes().token = mToken;
         dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_QS_DIALOG);
         dialog.show();
-        getQsTile().onShowDialog();
+        try {
+            mService.onShowDialog(mTile);
+        } catch (RemoteException e) {
+        }
     }
 
     /**
@@ -156,6 +203,11 @@
     public IBinder onBind(Intent intent) {
         return new IQSTileService.Stub() {
             @Override
+            public void setQSService(IQSService service) throws RemoteException {
+                mHandler.obtainMessage(H.MSG_SET_SERVICE, service).sendToTarget();
+            }
+
+            @Override
             public void setQSTile(Tile tile) throws RemoteException {
                 mHandler.obtainMessage(H.MSG_SET_TILE, tile).sendToTarget();
             }
@@ -194,6 +246,7 @@
         private static final int MSG_TILE_ADDED = 4;
         private static final int MSG_TILE_REMOVED = 5;
         private static final int MSG_TILE_CLICKED = 6;
+        private static final int MSG_SET_SERVICE = 7;
 
         public H(Looper looper) {
             super(looper);
@@ -202,11 +255,28 @@
         @Override
         public void handleMessage(Message msg) {
             switch (msg.what) {
+                case MSG_SET_SERVICE:
+                    mService = (IQSService) msg.obj;
+                    if (mTile != null) {
+                        mTile.setService(mService);
+                    }
+                    break;
                 case MSG_SET_TILE:
                     mTile = (Tile) msg.obj;
+                    if (mService != null && mTile != null) {
+                        mTile.setService(mService);
+                    }
                     break;
                 case MSG_TILE_ADDED:
-                    TileService.this.onTileAdded();
+                    int mode = TileService.this.onTileAdded();
+                    if (mService == null) {
+                        return;
+                    }
+                    try {
+                        mService.setTileMode(new ComponentName(TileService.this,
+                                TileService.this.getClass()), mode);
+                    } catch (RemoteException e) {
+                    }
                     break;
                 case MSG_TILE_REMOVED:
                     TileService.this.onTileRemoved();
@@ -230,4 +300,16 @@
             }
         }
     }
+
+    /**
+     * Requests that a tile be put in the listening state so it can send an update.
+     *
+     * This method is only applicable to tiles that return {@link #TILE_MODE_ACTIVE} from
+     * {@link #onTileAdded()}, and will do nothing otherwise.
+     */
+    public static final void requestListeningState(Context context, ComponentName component) {
+        Intent intent = new Intent(ACTION_REQUEST_LISTENING);
+        intent.putExtra(EXTRA_COMPONENT, component);
+        context.sendBroadcast(intent, Manifest.permission.BIND_QUICK_SETTINGS_TILE);
+    }
 }
diff --git a/core/java/android/util/LocaleList.java b/core/java/android/util/LocaleList.java
index 1becfb4..f22cde0 100644
--- a/core/java/android/util/LocaleList.java
+++ b/core/java/android/util/LocaleList.java
@@ -28,12 +28,6 @@
 import java.util.HashSet;
 import java.util.Locale;
 
-// TODO: We don't except too many LocaleLists to exist at the same time, and
-// we need access to the data at native level, so we should pass the data
-// down to the native level, create a map of every list seen there, take a
-// pointer back, and just keep that pointer in the Java-level object, so
-// things could be copied very quickly.
-
 /**
  * LocaleList is an immutable list of Locales, typically used to keep an
  * ordered user preferences for locales.
@@ -219,6 +213,20 @@
         }
     }
 
+    private static final String STRING_EN_XA = "en-XA";
+    private static final String STRING_AR_XB = "ar-XB";
+    private static final Locale LOCALE_EN_XA = new Locale("en", "XA");
+    private static final Locale LOCALE_AR_XB = new Locale("ar", "XB");
+    private static final int NUM_PSEUDO_LOCALES = 2;
+
+    private static boolean isPseudoLocale(String locale) {
+        return STRING_EN_XA.equals(locale) || STRING_AR_XB.equals(locale);
+    }
+
+    private static boolean isPseudoLocale(Locale locale) {
+        return LOCALE_EN_XA.equals(locale) || LOCALE_AR_XB.equals(locale);
+    }
+
     private static int matchScore(Locale supported, Locale desired) {
         if (supported.equals(desired)) {
             return 1;  // return early so we don't do unnecessary computation
@@ -226,6 +234,11 @@
         if (!supported.getLanguage().equals(desired.getLanguage())) {
             return 0;
         }
+        if (isPseudoLocale(supported) || isPseudoLocale(desired)) {
+            // The locales are not the same, but the languages are the same, and one of the locales
+            // is a pseudo-locale. So this is not a match.
+            return 0;
+        }
         // There is no match if the two locales use different scripts. This will most imporantly
         // take care of traditional vs simplified Chinese.
         final String supportedScr = getLikelyScript(supported);
@@ -233,24 +246,26 @@
         return supportedScr.equals(desiredScr) ? 1 : 0;
     }
 
-    /**
-     * Returns the first match in the locale list given an unordered array of supported locales
-     * in BCP47 format.
-     *
-     * If the locale list is empty, null would be returned.
-     */
-    @Nullable
-    public Locale getFirstMatch(String[] supportedLocales) {
+    private static final Locale EN_LATN = Locale.forLanguageTag("en-Latn");
+
+    private Locale computeFirstMatch(String[] supportedLocales, boolean assumeEnglishIsSupported) {
         if (mList.length == 1) {  // just one locale, perhaps the most common scenario
             return mList[0];
         }
         if (mList.length == 0) {  // empty locale list
             return null;
         }
-        // TODO: Figure out what to if en-XA or ar-XB are in the locale list
         int bestIndex = Integer.MAX_VALUE;
-        for (String tag : supportedLocales) {
-            final Locale supportedLocale = Locale.forLanguageTag(tag);
+        final int numSupportedLocales =
+                supportedLocales.length + (assumeEnglishIsSupported ? 1 : 0);
+        for (int i = 0; i < numSupportedLocales; i++) {
+            final Locale supportedLocale;
+            if (assumeEnglishIsSupported) {
+                // Try English first, so we can return early if it's in the LocaleList
+                supportedLocale = (i == 0) ? EN_LATN : Locale.forLanguageTag(supportedLocales[i-1]);
+            } else {
+                supportedLocale = Locale.forLanguageTag(supportedLocales[i]);
+            }
             // We expect the average length of locale lists used for locale resolution to be
             // smaller than three, so it's OK to do this as an O(mn) algorithm.
             for (int idx = 0; idx < mList.length; idx++) {
@@ -271,6 +286,47 @@
         }
     }
 
+    /**
+     * Returns the first match in the locale list given an unordered array of supported locales
+     * in BCP47 format.
+     *
+     * If the locale list is empty, null would be returned.
+     */
+    @Nullable
+    public Locale getFirstMatch(String[] supportedLocales) {
+        return computeFirstMatch(supportedLocales, false /* assume English is not supported */);
+    }
+
+    /**
+     * Same as getFirstMatch(), but with English assumed to be supported, even if it's not.
+     * {@hide}
+     */
+    @Nullable
+    public Locale getFirstMatchWithEnglishSupported(String[] supportedLocales) {
+        return computeFirstMatch(supportedLocales, true /* assume English is supported */);
+    }
+
+    /**
+     * Returns true if the array of locale tags only contains empty locales and pseudolocales.
+     * Assumes that there is no repetition in the input.
+     * {@hide}
+     */
+    public static boolean isPseudoLocalesOnly(String[] supportedLocales) {
+        if (supportedLocales.length > NUM_PSEUDO_LOCALES + 1) {
+            // This is for optimization. Since there's no repetition in the input, if we have more
+            // than the number of pseudo-locales plus one for the empty string, it's guaranteed
+            // that we have some meaninful locale in the list, so the list is not "practically
+            // empty".
+            return false;
+        }
+        for (String locale : supportedLocales) {
+            if (!locale.isEmpty() && !isPseudoLocale(locale)) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     private final static Object sLock = new Object();
 
     @GuardedBy("sLock")
diff --git a/core/java/android/view/IDockDividerVisibilityListener.aidl b/core/java/android/view/IDockedStackListener.aidl
similarity index 70%
rename from core/java/android/view/IDockDividerVisibilityListener.aidl
rename to core/java/android/view/IDockedStackListener.aidl
index a7d5cda..77fa7e2 100644
--- a/core/java/android/view/IDockDividerVisibilityListener.aidl
+++ b/core/java/android/view/IDockedStackListener.aidl
@@ -22,6 +22,15 @@
   *
   * @hide
   */
-oneway interface IDockDividerVisibilityListener {
-    void onDockDividerVisibilityChanged(boolean visible);
+oneway interface IDockedStackListener {
+
+    /**
+     * Will fire when an app is shown in side by side mode and a divider should be shown.
+     */
+    void onDividerVisibilityChanged(boolean visible);
+
+    /**
+     * Called when the docked stack gets created or removed.
+     */
+    void onDockedStackExistsChanged(boolean exists);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index 7a379d50..84d312d 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -29,7 +29,7 @@
 import android.os.IRemoteCallback;
 import android.view.IApplicationToken;
 import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
 import android.view.IWindowSession;
@@ -101,11 +101,14 @@
      *                   the task doesn't exist yet.
      * @param configuration Configuration that is being used with this task.
      * @param cropWindowsToStack True if the app windows should be cropped to the stack bounds.
+     * @param alwaysFocusable True if the app windows are always focusable regardless of the stack
+     *                        they are in.
      */
     void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showWhenLocked, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack);
+            in Rect taskBounds, in Configuration configuration, boolean cropWindowsToStack,
+            boolean alwaysFocusable);
     /**
      *
      * @param token The token we are adding to the input task Id.
@@ -354,7 +357,17 @@
     void setDockedStackResizing(boolean resizing);
 
     /**
-     * Registers a listener that will be called when the dock divider changes its visibility.
+     * Registers a listener that will be called when the dock divider changes its visibility or when
+     * the docked stack gets added/removed.
      */
-    void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener);
+    void registerDockedStackListener(IDockedStackListener listener);
+
+    /**
+     * Updates the dim layer used while resizing.
+     *
+     * @param visible Whether the dim layer should be visible.
+     * @param targetStackId The id of the task stack the dim layer should be placed on.
+     * @param alpha The translucency of the dim layer, between 0 and 1.
+     */
+    void setResizeDimLayer(boolean visible, int targetStackId, float alpha);
 }
diff --git a/core/java/android/view/TextureView.java b/core/java/android/view/TextureView.java
index 6b60be9..1be4810 100644
--- a/core/java/android/view/TextureView.java
+++ b/core/java/android/view/TextureView.java
@@ -297,7 +297,7 @@
 
     @Override
     public void setForeground(Drawable foreground) {
-        if (foreground != null) {
+        if (foreground != null && !sTextureViewIgnoresDrawableSetters) {
             throw new UnsupportedOperationException(
                     "TextureView doesn't support displaying a foreground drawable");
         }
@@ -305,7 +305,7 @@
 
     @Override
     public void setBackgroundDrawable(Drawable background) {
-        if (background != null) {
+        if (background != null && !sTextureViewIgnoresDrawableSetters) {
             throw new UnsupportedOperationException(
                     "TextureView doesn't support displaying a background drawable");
         }
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 537f887..3a1e9ab 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -812,6 +812,12 @@
     private static boolean sLayoutParamsAlwaysChanged = false;
 
     /**
+     * Allow setForeground/setBackground to be called (and ignored) on a textureview,
+     * without throwing
+     */
+    static boolean sTextureViewIgnoresDrawableSetters = false;
+
+    /**
      * This view does not want keystrokes. Use with TAKES_FOCUS_MASK when
      * calling setFlags.
      */
@@ -3984,6 +3990,10 @@
             // work. Partial layout breaks this assumption.
             sLayoutParamsAlwaysChanged = targetSdkVersion <= M;
 
+            // Prior to N, TextureView would silently ignore calls to setBackground/setForeground.
+            // On N+, we throw, but that breaks compatibility with apps that use these methods.
+            sTextureViewIgnoresDrawableSetters = targetSdkVersion <= M;
+
             sCompatibilityDone = true;
         }
     }
diff --git a/core/java/android/view/ViewGroup.java b/core/java/android/view/ViewGroup.java
index cd93dab..1c24392 100644
--- a/core/java/android/view/ViewGroup.java
+++ b/core/java/android/view/ViewGroup.java
@@ -1419,8 +1419,9 @@
 
         case DragEvent.ACTION_DRAG_ENDED: {
             // Release the bookkeeping now that the drag lifecycle has ended
-            if (mChildrenInterestedInDrag != null) {
-                for (View child : mChildrenInterestedInDrag) {
+            final HashSet<View> childrenInterestedInDrag = mChildrenInterestedInDrag;
+            if (childrenInterestedInDrag != null) {
+                for (View child : childrenInterestedInDrag) {
                     // If a child was interested in the ongoing drag, it's told that it's over
                     if (child.dispatchDragEvent(event)) {
                         retval = true;
@@ -1428,12 +1429,11 @@
                     child.mPrivateFlags2 &= ~View.DRAG_MASK;
                     child.refreshDrawableState();
                 }
-
-                mChildrenInterestedInDrag.clear();
-                if (mCurrentDragStartEvent != null) {
-                    mCurrentDragStartEvent.recycle();
-                    mCurrentDragStartEvent = null;
-                }
+                childrenInterestedInDrag.clear();
+            }
+            if (mCurrentDragStartEvent != null) {
+                mCurrentDragStartEvent.recycle();
+                mCurrentDragStartEvent = null;
             }
 
             if (mIsInterestedInDrag) {
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index f2b4fb3..1c9f3b4 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -3315,6 +3315,7 @@
                         && mPendingStableInsets.equals(args.arg6)
                         && mPendingVisibleInsets.equals(args.arg3)
                         && mPendingOutsets.equals(args.arg7)
+                        && mPendingBackDropFrame.equals(args.arg8)
                         && args.arg4 == null) {
                     break;
                 }
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
index 4b6e7e4..575ef02 100644
--- a/core/java/com/android/internal/app/ToolbarActionBar.java
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -483,6 +483,12 @@
         return true;
     }
 
+    @Override
+    public void onDestroy() {
+        // Remove any invalidation callbacks
+        mDecorToolbar.getViewGroup().removeCallbacks(mMenuInvalidator);
+    }
+
     public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
         mMenuVisibilityListeners.add(listener);
     }
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index bfc56db..4b821ab 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -36,6 +36,8 @@
     public static final int NOTIFICATION_TOPIC_NOTIFICATION = 263;
     public static final int ACTION_DEFAULT_SMS_APP_CHANGED = 264;
     public static final int QS_COLOR_MATRIX = 265;
+    public static final int QS_CUSTOM = 266;
+    public static final int ACTION_ZEN_ALLOW_SCREEN_ON = 267;
 
     /**
      * Logged when the user docks a window from recents by longpressing a task and dragging it to
diff --git a/core/jni/android/graphics/BitmapFactory.cpp b/core/jni/android/graphics/BitmapFactory.cpp
index 4a0f3fc..d8ec22a 100644
--- a/core/jni/android/graphics/BitmapFactory.cpp
+++ b/core/jni/android/graphics/BitmapFactory.cpp
@@ -587,10 +587,6 @@
     return doDecode(env, stream.release(), NULL, options);
 }
 
-static void nativeRequestCancel(JNIEnv*, jobject joptions) {
-    // Deprecated
-}
-
 static jboolean nativeIsSeekable(JNIEnv* env, jobject, jobject fileDescriptor) {
     jint descriptor = jniGetFDFromFileDescriptor(env, fileDescriptor);
     return ::lseek64(descriptor, 0, SEEK_CUR) != -1 ? JNI_TRUE : JNI_FALSE;
@@ -630,10 +626,6 @@
     },
 };
 
-static const JNINativeMethod gOptionsMethods[] = {
-    {   "requestCancel", "()V", (void*)nativeRequestCancel }
-};
-
 int register_android_graphics_BitmapFactory(JNIEnv* env) {
     jclass options_class = FindClassOrDie(env, "android/graphics/BitmapFactory$Options");
     gOptions_bitmapFieldID = GetFieldIDOrDie(env, options_class, "inBitmap",
@@ -665,8 +657,6 @@
     gInsetStruct_constructorMethodID = GetMethodIDOrDie(env, gInsetStruct_class, "<init>",
                                                         "(IIIIIIIIFIF)V");
 
-    android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory$Options",
-                                  gOptionsMethods, NELEM(gOptionsMethods));
     return android::RegisterMethodsOrDie(env, "android/graphics/BitmapFactory",
                                          gMethods, NELEM(gMethods));
 }
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index ab0df55..7c8dbe8 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -36,12 +36,12 @@
 namespace android {
 
 static jlong FontFamily_create(JNIEnv* env, jobject clazz, jstring lang, jint variant) {
-    FontLanguage fontLanguage;
-    if (lang != NULL) {
-        ScopedUtfChars str(env, lang);
-        fontLanguage = FontLanguage(str.c_str(), str.size());
+    if (lang == NULL) {
+        return (jlong)new FontFamily(variant);
     }
-    return (jlong)new FontFamily(fontLanguage, variant);
+    ScopedUtfChars str(env, lang);
+    uint32_t langId = FontStyle::registerLanguageList(str.c_str());
+    return (jlong)new FontFamily(langId, variant);
 }
 
 static void FontFamily_unref(JNIEnv* env, jobject clazz, jlong familyPtr) {
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index 654d148..0a25a0a 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -313,94 +313,10 @@
         obj->setTextAlign(align);
     }
 
-    // generate bcp47 identifier for the supplied locale
-    static void toLanguageTag(char* output, size_t outSize,
-            const char* locale) {
-        if (output == NULL || outSize <= 0) {
-            return;
-        }
-        if (locale == NULL) {
-            output[0] = '\0';
-            return;
-        }
-        char canonicalChars[ULOC_FULLNAME_CAPACITY];
-        UErrorCode uErr = U_ZERO_ERROR;
-        uloc_canonicalize(locale, canonicalChars, ULOC_FULLNAME_CAPACITY,
-                &uErr);
-        if (U_SUCCESS(uErr)) {
-            char likelyChars[ULOC_FULLNAME_CAPACITY];
-            uErr = U_ZERO_ERROR;
-            uloc_addLikelySubtags(canonicalChars, likelyChars,
-                    ULOC_FULLNAME_CAPACITY, &uErr);
-            if (U_SUCCESS(uErr)) {
-                uErr = U_ZERO_ERROR;
-                uloc_toLanguageTag(likelyChars, output, outSize, FALSE, &uErr);
-                if (U_SUCCESS(uErr)) {
-                    return;
-                } else {
-                    ALOGD("uloc_toLanguageTag(\"%s\") failed: %s", likelyChars,
-                            u_errorName(uErr));
-                }
-            } else {
-                ALOGD("uloc_addLikelySubtags(\"%s\") failed: %s",
-                        canonicalChars, u_errorName(uErr));
-            }
-        } else {
-            ALOGD("uloc_canonicalize(\"%s\") failed: %s", locale,
-                    u_errorName(uErr));
-        }
-        // unable to build a proper language identifier
-        output[0] = '\0';
-    }
-
-    static void toLanguageTags(std::string* output, const char* locales) {
-        if (output == NULL) {
-            return;
-        }
-        if (locales == NULL) {
-            output->clear();
-            return;
-        }
-
-        char langTag[ULOC_FULLNAME_CAPACITY];
-        const char* commaLoc = strchr(locales, ',');
-        if (commaLoc == NULL) {
-            assert(locales[0] != '\0');  // the string should not be empty
-            toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locales);
-            *output = langTag;
-            return;
-        }
-
-        size_t len = strlen(locales);
-        char locale[len];
-        output->clear();
-        output->reserve(len);
-        const char* lastStart = locales;
-        do {
-            assert(lastStart > commaLoc);  // the substring should not be empty
-            strncpy(locale, lastStart, commaLoc - lastStart);
-            locale[commaLoc - lastStart] = '\0';
-            toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, locale);
-            if (langTag[0] != '\0') {
-                output->append(langTag);
-                output->push_back(',');
-            }
-            lastStart = commaLoc + 1;
-            commaLoc = strchr(lastStart, ',');
-        } while (commaLoc != NULL);
-        assert(lastStart[0] != '\0');  // the final substring should not be empty
-        toLanguageTag(langTag, ULOC_FULLNAME_CAPACITY, lastStart);
-        if (langTag[0] != '\0') {
-            output->append(langTag);
-        }
-    }
-
     static jint setTextLocales(JNIEnv* env, jobject clazz, jlong objHandle, jstring locales) {
         Paint* obj = reinterpret_cast<Paint*>(objHandle);
         ScopedUtfChars localesChars(env, locales);
-        std::string buf;
-        toLanguageTags(&buf, localesChars.c_str());
-        jint minikinLangListId = FontStyle::registerLanguageList(buf);
+        jint minikinLangListId = FontStyle::registerLanguageList(localesChars.c_str());
         obj->setMinikinLangListId(minikinLangListId);
         return minikinLangListId;
     }
diff --git a/core/jni/android_util_AssetManager.cpp b/core/jni/android_util_AssetManager.cpp
index 90606a35..3473d9d 100644
--- a/core/jni/android_util_AssetManager.cpp
+++ b/core/jni/android_util_AssetManager.cpp
@@ -578,7 +578,7 @@
     return am->isUpToDate() ? JNI_TRUE : JNI_FALSE;
 }
 
-static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+static jobjectArray getLocales(JNIEnv* env, jobject clazz, bool includeSystemLocales)
 {
     Vector<String8> locales;
 
@@ -587,7 +587,7 @@
         return NULL;
     }
 
-    am->getLocales(&locales);
+    am->getLocales(&locales, includeSystemLocales);
 
     const int N = locales.size();
 
@@ -608,6 +608,16 @@
     return result;
 }
 
+static jobjectArray android_content_AssetManager_getLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, true /* include system locales */);
+}
+
+static jobjectArray android_content_AssetManager_getNonSystemLocales(JNIEnv* env, jobject clazz)
+{
+    return getLocales(env, clazz, false /* don't include system locales */);
+}
+
 static jobject constructConfigurationObject(JNIEnv* env, const ResTable_config& config) {
     jobject result = env->NewObject(gConfigurationOffsets.classObject,
             gConfigurationOffsets.constructor);
@@ -2154,6 +2164,8 @@
     // Resources.
     { "getLocales",      "()[Ljava/lang/String;",
         (void*) android_content_AssetManager_getLocales },
+    { "getNonSystemLocales", "()[Ljava/lang/String;",
+        (void*) android_content_AssetManager_getNonSystemLocales },
     { "getSizeConfigurations", "()[Landroid/content/res/Configuration;",
         (void*) android_content_AssetManager_getSizeConfigurations },
     { "setConfiguration", "!(IILjava/lang/String;IIIIIIIIIIIIII)V",
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 1090f90..c154e91 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -107,6 +107,7 @@
     <protected-broadcast android:name="android.backup.intent.CLEAR" />
     <protected-broadcast android:name="android.backup.intent.INIT" />
 
+    <protected-broadcast android:name="android.bluetooth.intent.DISCOVERABLE_TIMEOUT" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.STATE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.SCAN_MODE_CHANGED" />
     <protected-broadcast android:name="android.bluetooth.adapter.action.DISCOVERY_STARTED" />
@@ -888,6 +889,11 @@
         android:protectionLevel="normal"
         android:permissionFlags="hidden"/>
 
+    <!-- @hide We need to keep this around for backwards compatibility -->
+    <permission android:name="android.permission.FLASHLIGHT"
+        android:protectionLevel="normal"
+        android:permissionFlags="hidden"/>
+
     <!-- ====================================================================== -->
     <!-- INSTALL PERMISSIONS                                                    -->
     <!-- ====================================================================== -->
@@ -1193,14 +1199,6 @@
         android:description="@string/permdesc_vibrate"
         android:protectionLevel="normal" />
 
-    <!-- Allows access to the flashlight.
-         <p>Protection level: normal
-    -->
-    <permission android:name="android.permission.FLASHLIGHT"
-        android:label="@string/permlab_flashlight"
-        android:description="@string/permdesc_flashlight"
-        android:protectionLevel="normal" />
-
     <!-- Allows using PowerManager WakeLocks to keep processor from sleeping or screen
          from dimming.
          <p>Protection level: normal
@@ -1901,7 +1899,7 @@
 
     <!-- Allows an application to bind to third party quick settings tiles.
          <p>Should only be requested by the System, should be required by
-         QSTileService declarations.-->
+         TileService declarations.-->
     <permission android:name="android.permission.BIND_QUICK_SETTINGS_TILE"
         android:protectionLevel="signature" />
 
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index 04466e5..36c167e 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Laat die program toe om foto\'s en video\'s met die kamera te neem. Hierdie toestemming laat die program toe om die kamera te eniger tyd sonder jou bevestiging te gebruik."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"beheer vibrasie"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Laat die program toe om die vibrator te beheer."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"beheer flitslig"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Laat die program toe om die flitslig te beheer."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"skakel foonnommers direk"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Laat die program toe om telefoonnommers sonder jou tussentrede te bel. Dit kan tot onverwagte heffings of oproepe lei. Let daarop dat dit nie die program toelaat om noodnommers te bel nie. Kwaadwillige programme kan jou geld kos deur oproepe sonder jou bevestiging te maak."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot kitsboodskapoproepdiens"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index b262325..ec16add 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"መተግበሪያው በካሜራው ፎቶዎችንና ቪዲዮዎችን እንዲያነሳ ይፈቅድለታል። ይህ ፈቃድ መተግበሪያው ካሜራውን በማንኛውም ጊዜ ያላንተ ማረጋገጫ እንዲጠቀም ይፈቅድለታል።"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ነዛሪ ተቆጣጠር"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ነዛሪውን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"የብርሃንብልጭታ ተቆጣጠር"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"የብልጭታ ብርሃኑን ለመቆጣጠር ለመተግበሪያው ይፈቅዳሉ።"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"በቀጥታ ስልክ ቁጥሮች ደውል"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"መተግበሪያው ያላንተ ጣልቃ ገብነት የስልክ ቁጥሮች ላይ እንዲደውል ይፈቅድለታል። ይህ ያልተጠበቁ ክፍያዎችን ወይም ጥሪዎችን ሊያስከትል ይችላል። ይህ መተግበሪያው የድንገተኛ ስልክ ቁጥሮችን እንዲደውል እንደማይፈቅድለት ልብ በል። ተንኮል አዘል መተግበሪያዎች ያላንተ ማረጋገጫ ጥሪዎችን በማድረግ ገንዘብ ሊያስወጡህ ይችላሉ።"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"የአይኤምኤስ ጥሪ አገልግሎትን ይደርሳል"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 6eb005c..12ef759 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -358,8 +358,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"للسماح للتطبيق بالتقاط صور ومقاطع فيديو من خلال الكاميرا. ويتيح هذا الإذن للتطبيق استخدام الكاميرا في أي وقت وبدون موافقة منك."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"التحكم في الاهتزاز"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"للسماح للتطبيق بالتحكم في الهزّاز."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"التحكم في الضوء الوامض"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"للسماح للتطبيق بالتحكم في الضوء الوامض."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"اتصال مباشر بأرقام الهواتف"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"للسماح للتطبيق بطلب أرقام هاتفية بدون تدخل منك. وقد يؤدي ذلك إلى تحمل رسوم غير متوقعة أو إجراء مكالمات غير متوقعة. ومن الجدير بالذكر أن ذلك لا يتيح للتطبيق الاتصال بأرقام الطوارئ. وقد تؤدي التطبيقات الضارة إلى تحملك تكاليف مالية من خلال إجراء مكالمات بدون موافقة منك."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"الوصول إلى خدمة الاتصال عبر الرسائل الفورية"</string>
diff --git a/core/res/res/values-az-rAZ/strings.xml b/core/res/res/values-az-rAZ/strings.xml
index 30b6e77..7f0e6d7 100644
--- a/core/res/res/values-az-rAZ/strings.xml
+++ b/core/res/res/values-az-rAZ/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tətbiqə kamera ilə şəkil və video çəkməyə imkan yaradır. Bu icazə tətbiqə sizin təsdiqiniz olmadan kameradan istifadə icazəsi verir."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"vibrasiyaya nəzarət edir"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Tətbiqə vibratoru idarə etmə icazəsi verir."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"Flash işığını idarə edir"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Tətbiqə siqnal işığı na nəzarət etməyə imkan verir."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon nömrələrinə birbaşa zəng edir"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Tətbiqə Sizin müdaxiləniz olmadan telefon zəngləri etməyə imkan verir. Zərərli tətbiqlər Sizdən xəbərsiz şəkildə müxtəlif zənglər edərək, Sizə maddi ziyan vura bilər. Qeyd: Bu, tətbiqlərə təcili nömrələrə zəng etməyə icazə vermir."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS zəng xidmətinə giriş"</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 0f51f0d..ac5ce66 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -355,8 +355,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Dozvoljava aplikaciji da snima slike i video snimke kamerom. Ova dozvola omogućava aplikaciji da u bilo kom trenutku koristi kameru bez vaše potvrde."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrola vibracije"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Dozvoljava aplikaciji da kontroliše vibraciju."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrola osvetljenja"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Dozvoljava aplikaciji da kontroliše blic."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"direktno pozivanje brojeva telefona"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Dozvoljava aplikaciji da poziva brojeve telefona bez vaše dozvole. Ovo može da dovede do neočekivanih troškova ili poziva. Imajte na umu da ovo ne dozvoljava aplikaciji da poziva brojeve za hitne slučajeve. Zlonamerne aplikacije mogu da pozivaju bez vaše potvrde, što može da dovede do troškova."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristup usluzi poziva pomoću razmene trenutnih poruka"</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d70f95f..301e1e3 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Разрешава на приложението да прави снимки и видеоклипове с камерата. Това разрешение му позволява да я използва по всяко време без потвърждение от ваша страна."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контролиране на вибрирането"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Разрешава на приложението да контролира устройството за вибрация."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контролиране на фенерчето"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Разрешава на приложението да контролира фенерчето."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"директно обаждане до телефонни номера"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Разрешава на приложението да се обажда без ваша намеса до телефонни номера, което може да доведе до неочаквано таксуване или обаждания. Обърнете внимание, че това не му позволява да извършва обаждания до спешните служби. Злонамерените приложения могат да ви въвлекат в разходи, като извършват обаждания без потвърждение от ваша страна."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"достъп до услугата за незабавни съобщения за обаждания"</string>
diff --git a/core/res/res/values-bn-rBD/strings.xml b/core/res/res/values-bn-rBD/strings.xml
index 683e2ec..9c88d44 100644
--- a/core/res/res/values-bn-rBD/strings.xml
+++ b/core/res/res/values-bn-rBD/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ক্যামেরার সাহায্যে ছবি তুলতে ও ভিডিও তৈরি করতে অ্যাপ্লিকেশানটিকে মঞ্জুর করে৷ এই অনুমতিটি অ্যাপ্লিকেশানটিকে আপনার নিশ্চয়তা ছাড়াই যেকোনো সময় ক্যামেরা ব্যবহার করতে মঞ্জুর করে৷"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"কম্পন নিয়ন্ত্রণ করুন"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"অ্যাপ্লিকেশানকে কম্পক নিয়ন্ত্রণ করতে দেয়৷"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ফ্ল্যাশলাইট নিয়ন্ত্রণ করে"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"অ্যাপ্লিকেশানকে টর্চলাইট নিয়ন্ত্রণ করতে দেয়৷"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"সরাসরি ফোন নম্বরগুলিতে কল করে"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"অ্যাপ্লিকেশানটিকে আপনার হস্তক্ষেপ ছাড়াই ফোন নম্বরগুলিতে কল করতে মঞ্জুর করে৷ এটি অপ্রত্যাশিত পরিমাণ খরচা বা কলের কারণ হতে পারে৷ মনে রাখবেন, এটি অ্যাপ্লিকেশানটির দ্বারা জরুরি নম্বরগুলিতে কল করাকে অনুমতি দেয় না৷ ক্ষতিকারক অ্যাপ্লিকেশানগুলি আপনার সম্মতি ছাড়াই কল করার ফলে আপনাকে অহেতুক অর্থ প্রদান করতে হতে পারে৷"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS পরিষেবাতে অ্যাক্সেস"</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 786fea1..8554b843 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet que l\'aplicació faci fotos i vídeos amb la càmera. Aquest permís permet que l\'aplicació utilitzi la càmera en qualsevol moment sense la teva confirmació."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibració"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet que l\'aplicació controli el vibrador."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controla la llanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet que l\'aplicació controli la llanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"trucar directament a números de telèfon"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet que l\'aplicació truqui a números de telèfon sense la teva intervenció. Aquesta acció pot produir càrrecs o trucades inesperades. Tingues en compte que això no permet que l\'aplicació truqui a números d\'emergència. Les aplicacions malicioses poden fer trucades sense la teva confirmació, cosa que et pot fer gastar diners."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accés al servei de trucades IMS"</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index a2e12a3..2eca49a 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikaci pořizovat fotografie a videa pomocí fotoaparátu. Toto oprávnění umožňuje aplikaci používat fotoaparát kdykoliv i bez vašeho svolení."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ovládání vibrací"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikaci ovládat vibrace."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládání kontrolky"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikaci ovládat svítilnu."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"přímé volání na telefonní čísla"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikaci volat na telefonní čísla bez vašeho přičinění. Může mít za následek neočekávané poplatky nebo hovory. Toto oprávnění neumožňuje aplikaci volat na tísňová čísla. Škodlivé aplikace vás mohou připravit o peníze uskutečňováním hovorů bez vašeho svolení."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"přístup ke službě zasílání rychlých zpráv pro účely hovorů"</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 67b8ee9..2a719b0 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tillader, at appen kan tage billeder og videoer med kameraet. Med denne tilladelse kan appen til enhver tid bruge kameraet uden din bekræftelse."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillader, at appen kan kontrollere vibratoren."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontroller lommelygte"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillader, at appen kan kontrollere lommelygten."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ringe direkte op til telefonnumre"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Tillader, at appen kan ringe til telefonnumre uden din indgriben. Dette kan resultere i uventede opkrævninger eller opkald. Bemærk, at appen med denne tilladelse ikke kan ringe til nødopkaldsnumre. Skadelige apps kan koste dig penge ved at foretage opkald uden din bekræftelse."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"få adgang til chat-opkaldstjeneste"</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 2d64aee..d116a24 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ermöglicht der App, Bilder und Videos mit der Kamera aufzunehmen. Die Berechtigung erlaubt der App, die Kamera jederzeit und ohne Ihre Bestätigung zu nutzen."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"Vibrationsalarm steuern"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ermöglicht der App, den Vibrationsalarm zu steuern"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"Lichtanzeige steuern"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ermöglicht der App, die Lichtanzeige zu steuern"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"Telefonnummern direkt anrufen"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ermöglicht der App, ohne Ihr Eingreifen Telefonnummern zu wählen. Dies kann zu unerwarteten Kosten und Anrufen führen. Beachten Sie, dass die App keine Notrufnummern wählen kann. Schädliche Apps verursachen möglicherweise Kosten, indem sie Anrufe ohne Ihre Bestätigung tätigen."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Zugriff auf IMS-Anrufdienst"</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index a1a6ced..8116b16 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Επιτρέπει στην εφαρμογή τη λήψη φωτογραφιών και βίντεο με τη φωτογραφική μηχανή. Αυτή η άδεια δίνει τη δυνατότητα στην εφαρμογή να χρησιμοποιεί τη φωτογραφική μηχανή ανά πάσα στιγμή χωρίς την έγκρισή σας."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"έλεγχος δόνησης"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Επιτρέπει στην εφαρμογή τον έλεγχο της δόνησης."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"έλεγχος φακού"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Επιτρέπει στην εφαρμογή τον έλεγχο του φακού."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"απευθείας κλήση τηλεφωνικών αριθμών"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Επιτρέπει στην εφαρμογή την κλήση αριθμών τηλεφώνου χωρίς δική σας παρέμβαση. Αυτό μπορεί να προκαλέσει μη αναμενόμενες χρεώσεις ή κλήσεις. Έχετε υπόψη ότι δεν επιτρέπεται στην εφαρμογή η κλήση αριθμών έκτακτης ανάγκης. Οι κακόβουλες εφαρμογές ενδέχεται να σας κοστίσουν χρήματα, πραγματοποιώντας κλήσεις χωρίς την έγκρισή σας."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"πρόσβαση στην υπηρεσία κλήσεων της IMS"</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index cd2dc23..930c310 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index cd2dc23..930c310 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index cd2dc23..930c310 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Allows the app to take pictures and videos with the camera. This permission allows the app to use the camera at any time without your confirmation."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"control vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Allows the app to control the vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Allows the app to control the flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"directly call phone numbers"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Allows the app to call phone numbers without your intervention. This may result in unexpected charges or calls. Note that this doesn\'t allow the app to call emergency numbers. Malicious apps may cost you money by making calls without your confirmation."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"access IMS call service"</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index a6f76ac..258ef33 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación saque fotos o grabe videos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la vibración."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas a números de teléfono sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio IMS para realizar llamadas"</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 594fa50..9848bb6 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que la aplicación haga fotos o grabe vídeos con la cámara. Este permiso autoriza a la aplicación a utilizar la cámara en cualquier momento sin tu confirmación."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar la vibración"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que la aplicación controle la función de vibración."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar linterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que la aplicación controle la función de linterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"llamar directamente a números de teléfono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que la aplicación haga llamadas sin intervención del usuario, lo que puede dar lugar a llamadas o cargos inesperados. Ten en cuenta que las aplicaciones no pueden usar este servicio para realizar llamadas a números de emergencia, pero las aplicaciones malintencionadas pueden causarte gastos imprevistos al realizar llamadas sin tu confirmación."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceder al servicio de llamadas IMS"</string>
diff --git a/core/res/res/values-et-rEE/strings.xml b/core/res/res/values-et-rEE/strings.xml
index 8ee8904..466bd5d 100644
--- a/core/res/res/values-et-rEE/strings.xml
+++ b/core/res/res/values-et-rEE/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Võimaldab rakendusel teha kaameraga pilte ja videoid. See luba võimaldab rakendusel kasutada kaamerat mis tahes ajal teie kinnituseta."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"juhtige vibreerimist"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Võimaldab rakendusel juhtida vibreerimist."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"juhi taskulampi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Võimaldab rakendusel juhtida taskulampi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"helista otse telefoninumbritele"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Võimaldab rakendusel teie sekkumiseta telefoninumbritele helistada. See võib põhjustada ootamatuid tasusid või telefonikõnesid. Pange tähele, et see ei luba rakendusel helistada hädaabinumbritele. Pahatahtlikud rakendused võivad teile kulusid tekitada, tehes telefonikõnesid teie kinnituseta."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"juurdepääs IMS-kõneteenusele"</string>
diff --git a/core/res/res/values-eu-rES/strings.xml b/core/res/res/values-eu-rES/strings.xml
index e257fe9..cdb8622 100644
--- a/core/res/res/values-eu-rES/strings.xml
+++ b/core/res/res/values-eu-rES/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Kamerarekin argazkiak ateratzeko eta bideoak grabatzeko baimena ematen die aplikazioei. Baimen horrekin, aplikazioak kamera edonoiz erabil dezake zure baimenik gabe."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"bibrazioa kontrolatzea"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Bibragailua kontrolatzea baimentzen die aplikazioei."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolatu linterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Linterna kontrolatzea baimentzen die aplikazioei."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"deitu zuzenean telefono-zenbakietara"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Telefono-zenbakietara zuk esku hartu gabe deitzeko baimena ematen die aplikazioei. Horrela, ustekabeko gastuak edo deiak eragin daitezke. Aplikazio gaiztoek erabil dezakete zuk berretsi gabeko deiak eginda gastuak eragiteko."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Atzitu IMS dei-zerbitzua"</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index b6b669e..b0da5fe 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"به برنامه اجازه می‌دهد با دوربین به عکسبرداری و فیلمبرداری بپردازد. این مجوز به برنامه اجازه می‌‌دهد از دوربین در هر زمانی بدون تأیید شما استفاده کند."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"کنترل لرزش"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"‏به برنامه اجازه می‎دهد تا لرزاننده را کنترل کند."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"کنترل چراغ قوه"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"‏به برنامه اجازه می‎دهد تا چراغ قوه را کنترل کند."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"تماس مستقیم با شماره تلفن‌ها"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"به برنامه اجازه می‌دهد بدون دخالت شما با شماره‌های تلفن تماس بگیرد. این ممکن است باعث ایجاد هزینه یا تماس‌های پیش‌بینی نشده شود. توجه داشته باشید که این به برنامه اجازه نمی‌دهد به برقراری تماس‌های اضطراری بپردازد. برنامه‌های مخرب ممکن است با برقراری تماس بدون تأیید شما هزینه‌هایی را برای شما ایجاد کنند."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏دسترسی به سرویس تماس IMS"</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index b0efd96..f7db678 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Antaa sovelluksen ottaa kuvia ja kuvata videoita kameralla. Sovellus voi käyttää kameraa milloin tahansa ilman lupaasi."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"hallitse värinää"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Antaa sovelluksen hallita värinää."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"hallitse taskulamppua"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Antaa sovelluksen hallita taskulamppua."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"soittaa puhelinnumeroihin suoraan"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Antaa sovelluksen soittaa puhelinnumeroihin kysymättä sinulta. Tämä voi aiheuttaa odottamattomia kuluja tai puheluita. Huomaa, että tämä ei anna sovellukselle lupaa soittaa hätänumeroihin. Haitalliset sovellukset voivat aiheuttaa sinulle kuluja soittamalla puheluita ilman lupaa."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pikaviestipalvelun puhelukäyttöoikeus"</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 52a47587..50aed95 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"gérer le vibreur"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de gérer le vibreur de l\'appareil."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"gérer la lampe de poche"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de gérer la lampe de poche."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement des numéros de téléphone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Des applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 2740f3d..33d2016 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permet à l\'application de prendre des photos et de filmer des vidéos avec l\'appareil photo. Cette autorisation lui permet d\'utiliser l\'appareil photo à tout moment sans votre consentement."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"contrôler le vibreur"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permet à l\'application de contrôler le vibreur."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"contrôler la lampe de poche"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permet à l\'application de contrôler la lampe de poche."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"appeler directement les numéros de téléphone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permet à l\'application d\'appeler des numéros de téléphone sans votre intervention. Cette autorisation peut entraîner des frais ou des appels imprévus et ne permet pas à l\'application d\'appeler des numéros d\'urgence. Les applications malveillantes peuvent générer des frais en passant des appels sans votre consentement."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accéder au service d\'appel IMS"</string>
diff --git a/core/res/res/values-gl-rES/strings.xml b/core/res/res/values-gl-rES/strings.xml
index 71ce6e9b..7947825 100644
--- a/core/res/res/values-gl-rES/strings.xml
+++ b/core/res/res/values-gl-rES/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite á aplicación tomar imaxes e vídeos coa cámara. Con este permiso a aplicación pode utilizar a cámara en calquera momento sen a túa confirmación."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar a vibración"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite á aplicación controlar o vibrador."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar a lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite á aplicación controlar a luz do flash."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"chamar directamente aos números de teléfono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite á aplicación chamar a números de teléfono sen a túa intervención. Esta acción pode implicar chamadas ou custos inesperados. Ten en conta que isto non permite á aplicación chamar a números de emerxencia. É posible que aplicacións maliciosas che custen diñeiro debido á realización de chamadas sen a túa confirmación."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acceso ao servizo de chamadas de IMS"</string>
diff --git a/core/res/res/values-gu-rIN/strings.xml b/core/res/res/values-gu-rIN/strings.xml
index 8258dc2..aa9478b 100644
--- a/core/res/res/values-gu-rIN/strings.xml
+++ b/core/res/res/values-gu-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"એપ્લિકેશનને કૅમેરા વડે ચિત્રો અને વિડિઓઝ લેવાની મંજૂરી આપે છે. આ પરવાનગી એપ્લિકેશનને તમારી પુષ્ટિ વિના કોઈપણ સમયે કૅમેરાના ઉપયોગની મંજૂરી આપે છે."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"વાઇબ્રેશન નિયંત્રિત કરો"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"એપ્લિકેશનને વાઇબ્રેટરને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ફ્લેશલાઇટ નિયંત્રિત કરો"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"એપ્લિકેશનને ફ્લેશલાઇટને નિયંત્રિત કરવાની મંજૂરી આપે છે."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"સીધા જ ફોન નંબર્સ પર કૉલ કરો"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"એપ્લિકેશનને તમારા હસ્તક્ષેપ વિના ફોન નંબર્સ પર કૉલ કરવાની મંજૂરી આપે છે. આ અનપેક્ષિત શુલ્ક અથવા કૉલ્સમાં પરિણમી શકે છે. નોંધો કે આ એપ્લિકેશનને કટોકટીના નંબર્સ પર કૉલ કરવાની મંજૂરી આપતું નથી. દુર્ભાવનાપૂર્ણ એપ્લિકેશનો તમારી પુષ્ટિ વિના કૉલ્સ કરીને તમારા પૈસા ખર્ચ કરી શકે છે."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS કૉલ સેવા ઍક્સેસ કરો"</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index 3f374ac6..d3d1e2c 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ऐप्स  को कैमरे से चित्र और वीडियो लेने देता है. यह अनुमति ऐप्स  को किसी भी समय आपकी पुष्टि के बिना कैमरे का उपयोग करने देती है."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करें"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ऐप्स को कंपनकर्ता नियंत्रित करने देता है."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"फ़्लैशलाइट नियंत्रित करें"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ऐप्स को फ़्लैशलाइट नियंत्रित करने देता है."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फ़ोन नंबर पर सीधे कॉल करें"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ऐप्स  को आपके हस्‍तक्षेप के बिना फ़ोन नंबर पर कॉल करने देता है. इसके परिणाम अप्रत्‍याशित शुल्‍क या कॉल हो सकते हैं. ध्यान दें कि यह ऐप्स  को आपातकालीन नंबर पर कॉल नहीं करने देता. दुर्भावनापूर्ण ऐप्स  आपकी पुष्टि के बिना कॉल करके आपका धन व्‍यय कर सकते हैं."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवा ऐक्‍सेस करें"</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index bf89366..dc55c57 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -355,8 +355,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogućuje snimanje slika i videozapisa fotoaparatom. Ta dozvola aplikaciji omogućuje upotrebu fotoaparata u bilo kojem trenutku bez vašeg odobrenja."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"upravljanje vibracijom"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogućuje nadzor nad vibratorom."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"upravljanje svjetiljkom"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogućuje upravljanje svjetiljkom."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"izravno pozivanje telefonskog broja"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogućuje pozivanje telefonskih brojeva bez vašeg sudjelovanja. To može dovesti do neočekivanih troškova ili poziva. Uzmite u obzir da se aplikaciji time ne omogućuje pozivanje brojeva u nuždi. Zlonamjerne aplikacije mogu vam uzrokovati dodatne troškove postavljanjem poziva bez vašeg odobrenja."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pristupiti usluzi poziva izravnih poruka"</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index 64e2229..3176c65 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Lehetővé teszi az alkalmazás számára, hogy a fényképezőgéppel fotókat és videókat készítsen. Az engedéllyel rendelkező alkalmazás bármikor, az Ön jóváhagyása nélkül használhatja a fényképezőgépet."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"rezgés szabályozása"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Lehetővé teszi az alkalmazás számára a rezgés vezérlését."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"vaku vezérlése"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Lehetővé teszi az alkalmazás számára a vaku vezérlését."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefonszámok közvetlen hívása"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Lehetővé teszi az alkalmazás számára, hogy az Ön jóváhagyása nélkül hívjon fel telefonszámokat. Ennek eredményeként váratlan terhelésekkel vagy telefonhívásokkal találkozhat. Vegye figyelembe, hogy ez nem teszi lehetővé segélyhívó számok hívását az alkalmazás számára. A rosszindulatú alkalmazások az Ön jóváhagyása nélkül kezdeményezhetnek hívásokat, így költségek merülhetnek fel."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"hozzáférés az IMS-hívásszolgáltatáshoz"</string>
diff --git a/core/res/res/values-hy-rAM/strings.xml b/core/res/res/values-hy-rAM/strings.xml
index 6fdccd3..d72ee8d 100644
--- a/core/res/res/values-hy-rAM/strings.xml
+++ b/core/res/res/values-hy-rAM/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Թույլ է տալիս հավելվածին ֆոտոխցիկով լուսանկարել և տեսանկարել: Այս թույլտվությունը հնարավորություն է տալիս հավելվածին օգտագործել ֆոտոխցիկը ցանկացած ժամանակ` առանց ձեր հաստատման:"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"կառավարել թրթռումը"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Թույլ է տալիս հավելվածին կառավարել թրթռոցը:"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"կառավարել լապտերը"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Թույլ է տալիս հավելվածին կառավարել լապտերը:"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ուղղակիորեն զանգել հեռախոսահամարներին"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Թույլ է տալիս հավելվածին զանգել հեռախոսահամարներին առանց ձեր միջամտության: Սա կարող է հանգեցնել անկանխատեսելի գանձումների կամ զանգերի: Նկատի ունեցեք, որ սա թույլ չի տալիս հավելվածին զանգել արտակարգ իրավիճակների համարներին: Վնասարար հավելվածները կարող են ձեր հաշվից զանգեր կատարել` առանց ձեր հաստատման:"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"օգտվել IMS զանգերի ծառայությունից"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 4960267..024eea4 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Memungkinkan aplikasi mengambil gambar dan video dengan kamera. Izin ini memungkinkan aplikasi menggunakan kamera kapan saja tanpa konfirmasi Anda."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrol getaran"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Mengizinkan aplikasi untuk mengendalikan vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"mengontrol lampu senter"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Mengizinkan apl mengontrol lampu kilat."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"panggil nomor telepon secara langsung"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Memungkinkan aplikasi menghubungi nomor telepon tanpa campur tangan Anda. Izin ini dapat mengakibatkan biaya atau panggilan tak terduga. Perhatikan bahwa izin ini tidak memungkinkan aplikasi menghubungi nomor darurat. Aplikasi berbahaya dapat menyebabkan Anda dikenakan biaya dengan melakukan panggilan tanpa konfirmasi Anda."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses layanan panggilan IMS"</string>
diff --git a/core/res/res/values-is-rIS/strings.xml b/core/res/res/values-is-rIS/strings.xml
index 35ae53d..240c715 100644
--- a/core/res/res/values-is-rIS/strings.xml
+++ b/core/res/res/values-is-rIS/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Leyfir forriti að taka myndir og myndskeið með myndavélinni. Þessi heimild leyfir forritinu að nota myndavélina hvenær sem er án þinnar heimildar."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"stjórna titringi"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Leyfir forriti að stjórna titraranum."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"stjórna vasaljósi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Leyfir forriti að stjórna vasaljósinu."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"hringja beint í símanúmer"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Leyfir forriti að hringja í símanúmer án íhlutunar notanda. Þetta getur haft í för með sér óumbeðin gjöld og símtöl. Athugaðu að þetta leyfir forritinu ekki að hringja í neyðarnúmer. Spilliforrit geta stofnað til kostnaðar fyrir þig með því að hringja símtöl án þinnar heimildar."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"fá aðgang að IMS-símtalsþjónustu"</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index ee1b67d..ece503d 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Consente all\'applicazione di scattare foto e riprendere video con la fotocamera. Questa autorizzazione consente all\'applicazione di utilizzare la fotocamera in qualsiasi momento senza la tua conferma."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controllo vibrazione"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Consente all\'applicazione di controllare la vibrazione."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controllo flash"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Consente all\'applicazione di controllare il flash."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"chiamata diretta n. telefono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Consente all\'applicazione di chiamare numeri di telefono senza il tuo intervento. Ciò può comportare chiamate o addebiti imprevisti. Tieni presente che ciò non consente all\'applicazione di chiamare numeri di emergenza. Applicazioni dannose potrebbero generare dei costi effettuando chiamate senza la tua conferma."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"Accesso al servizio di chiamata IMS"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index df0471e..144afc0 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"מאפשר לאפליקציה לצלם תמונות וסרטונים באמצעות המצלמה. אישור זה מאפשר לאפליקציה להשתמש במצלמה בכל עת ללא אישורך."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"שליטה ברטט"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"מאפשר לאפליקציה לשלוט ברטט."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"שליטה בפנס"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"מאפשר לאפליקציה לשלוט בפנס."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"התקשר ישירות למספרי טלפון"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"מאפשר לאפליקציה להתקשר למספרי טלפון ללא התערבותך. פעולה זו עשויה לגרום לשיחות או לחיובים לא צפויים. שים לב שהדבר לא מאפשר לאפליקציה להתקשר למספרי חירום. אפליקציות זדוניות עשויות לגרום לעלויות על ידי ביצוע שיחות ללא התערבותך."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏גישה אל שירות שיחות IMS"</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 764e0cf..edfab22 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"カメラでの写真と動画の撮影をアプリに許可します。これにより、アプリが確認なしでいつでもカメラを使用できるようになります。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"バイブレーションの制御"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"バイブレーションの制御をアプリに許可します。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ライトのコントロール"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ライトの制御をアプリに許可します。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"電話番号発信"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"電話番号への自動発信をアプリに許可します。これにより、予期せぬ発信や料金が発生する可能性があります。なお、緊急通報番号への発信は許可されません。悪意のあるアプリが確認なしで発信し、料金が発生する恐れがあります。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS通話サービスへのアクセス"</string>
diff --git a/core/res/res/values-ka-rGE/strings.xml b/core/res/res/values-ka-rGE/strings.xml
index 0fa786c..ffdd31c 100644
--- a/core/res/res/values-ka-rGE/strings.xml
+++ b/core/res/res/values-ka-rGE/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"აპს შეეძლება კამერით სურათისა და ვიდეოს გადაღება. ეს ნებართვა აპს უფლებას აძლევს, ნებისმიერ დროს გამოიყენოს კამერა თქვენი დადასტურების გარეშე."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ვიბრაციის კონტროლი"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"აპს შეეძლება, მართოს ვიბრირება."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ფანრის მართვა"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"აპს შეეძლება, მართოს განათება."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"პირდაპირი დარეკვა ტელეფონის ნომრებზე"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"აპს შეეძლება დარეკოს ტელეფონის ნომრებზე თქვენი ჩარევის გარეშე. ამან შესაძლოა გამოიწვიოს თქვენს სატელეფონი ქვითარზე მოულოდნელი ხარჯებისა და ზარების გაჩენა. გაითვალისწინეთ, რომ აპს გადაუდებელი დახმარების ნომრებზე დარეკვა არ შეუძლია. მავნე აპებს შეეძლება თქვენი დადასტურების გარეშე ზარების განხორციელება და შესაბამისი საფასურის გადახდაც მოგიწევთ."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ზარების სერვისზე წვდომა"</string>
diff --git a/core/res/res/values-kk-rKZ/strings.xml b/core/res/res/values-kk-rKZ/strings.xml
index 275e5bc..ff58eaa 100644
--- a/core/res/res/values-kk-rKZ/strings.xml
+++ b/core/res/res/values-kk-rKZ/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Қолданбаға камераны қолданып, фотосурет немесе бейне жазу мүмкіндігін береді. Бұл рұқсат камераны кез келген уақытта сіздің құптауыңызды қажет етпей қолдану мүмкіндігін береді."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"тербелісті басқару"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Қолданбаға вибраторды басқаруға рұқсат береді."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"сигналдық шамды басқару"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Қолданбаға қалта шамын басқаруға рұқсат береді."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"нөмірлерге тікелей телефон шалу"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Қолданбаға сіздің қатысуыңызсыз қоңырау шалу мүмкіндігін береді. Нәтижесінде қосымша төлем немесе күтпеген қоңырау алуыңыз мүмкін. Есіңізде болсын, қолданба төтенше байланыстарға қоңырау шала алмайды. Залалды қолданбалар сіздің рұқсатыңызсыз қоңыраулар шалып, күтпеген төлемдерге себеп болуы мүмкін."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS қоңырау қызметін пайдалану"</string>
diff --git a/core/res/res/values-km-rKH/strings.xml b/core/res/res/values-km-rKH/strings.xml
index 96abf45..261212f 100644
--- a/core/res/res/values-km-rKH/strings.xml
+++ b/core/res/res/values-km-rKH/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ឲ្យ​កម្មវិធី​ថត​រូប និង​វីដេអូ​ដោយ​ប្រើ​ម៉ាស៊ីន​ថត។ វា​ឲ្យ​កម្មវិធី​​ប្រើ​ម៉ាស៊ីន​ថត​នៅ​ពេល​​ណាមួយ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ពិនិត្យ​ការ​ញ័រ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ឲ្យ​កម្មវិធី​គ្រប់គ្រង​កម្មវិធី​ញ័រ។"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ត្រួតពិនិត្យ​ពិល"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ឲ្យ​កម្មវិធី​ពិនិត្យ​ពិល។"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​ផ្ទាល់"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ឲ្យ​កម្មវិធី​ហៅ​លេខ​ទូរស័ព្ទ​ដោយ​គ្មាន​សកម្មភាព​របស់​អ្នក។​ វា​អាច​កាត់​លុយ​ ឬ​ហៅ​ដោយ​មិន​រំពឹង​ទុក។ ចំណាំ​ថា​ វា​មិន​អនុញ្ញាត​ឲ្យ​កម្មវិធី​ហៅ​លេខ​ពេល​អាសន្ន​ទេ។ កម្មវិធី​ព្យាបាទ​អាច​កាត់​លុយ​របស់​អ្នក​ ដោយ​ធ្វើការ​ហៅ​ដោយ​គ្មាន​ការ​បញ្ជាក់​របស់​អ្នក។"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"ចូលដំណើរការសេវាកម្មការហៅតាម IMS"</string>
diff --git a/core/res/res/values-kn-rIN/strings.xml b/core/res/res/values-kn-rIN/strings.xml
index d0dac23..f083702 100644
--- a/core/res/res/values-kn-rIN/strings.xml
+++ b/core/res/res/values-kn-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ಕ್ಯಾಮರಾ ಮೂಲಕ ಚಿತ್ರಗಳು ಮತ್ತು ವೀಡಿಯೊಗಳನ್ನು ಸೆರೆಹಿಡಿಯಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅವಕಾಶ ಮಾಡಿಕೊಡುತ್ತದೆ. ಈ ಅನುಮತಿಯು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಯಾವುದೇ ಸಮಯದಲ್ಲಿ ಕ್ಯಾಮರಾವನ್ನು ಬಳಸಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ವೈಬ್ರೇಷನ್‌‌ ನಿಯಂತ್ರಿಸಿ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ವೈಬ್ರೇಟರ್‌ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ನಿಯಂತ್ರಿಸಿ"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ಫ್ಲ್ಯಾಶ್‌ಲೈಟ್ ನಿಯಂತ್ರಿಸಲು ಅಪ್ಲಿಕೇಶನ್‌‌ಗೆ ಅನುಮತಿಸುತ್ತದೆ."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ಫೋನ್ ಸಂಖ್ಯೆಗಳಿಗೆ ನೇರವಾಗಿ ಕರೆ ಮಾಡಿ"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ನಿಮ್ಮ ಹಸ್ತಕ್ಷೇಪ ಇಲ್ಲದೆಯೇ ಫೋನ್‍ ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆ ಮಾಡಲು ಅಪ್ಲಿಕೇಶನ್‍‍ಗೆ ಅನುಮತಿಸುತ್ತದೆ. ಇದು ಅನಿರೀಕ್ಷಿತ ಶುಲ್ಕಗಳು ಅಥವಾ ಕರೆಗಳಿಗೆ ಕಾರಣವಾಗಬಹುದು. ತುರ್ತು ಸಂಖ್ಯೆಗಳಿಗೆ ಕರೆಮಾಡಲು ಈ ಅಪ್ಲಿಕೇಶನ್‍ ಅನುಮತಿಸುವುದಿಲ್ಲ ಎಂಬುದು ಗಮನದಲ್ಲಿರಲಿ. ದುರುದ್ದೇಶಪೂರಿತ ಅಪ್ಲಿಕೇಶನ್‍‍ಗಳು ನಿಮ್ಮ ಖಾತರಿ ಇಲ್ಲದೆಯೇ ಕರೆಗಳನ್ನು ಮಾಡುವುದರ ಮೂಲಕ ನಿಮ್ಮ ಹಣ ಖರ್ಚಾಗಬಹುದು."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ಕರೆ ಸೇವೆಯನ್ನು ಪ್ರವೇಶಿಸಿ"</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index b1b4588..c8f08c7 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"앱이 카메라로 사진과 동영상을 찍을 수 있도록 허용합니다. 이 권한을 사용하면 앱이 언제든지 사용자의 확인 없이 카메라를 사용할 수 있습니다."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"진동 제어"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"앱이 진동을 제어할 수 있도록 허용합니다."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"카메라 플래시 제어"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"앱이 카메라 플래시를 제어할 수 있도록 허용합니다."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"전화번호 자동 연결"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"앱이 사용자의 조작 없이 전화번호로 전화를 걸 수 있도록 허용합니다. 이 경우 예상치 못한 통화 요금이 부과될 수 있습니다. 앱이 비상 전화를 걸도록 하는 권한은 주어지지 않습니다. 악성 앱이 사용자의 확인 없이 전화를 걸어 요금이 부과될 수 있습니다."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS 통화 서비스에 액세스"</string>
diff --git a/core/res/res/values-ky-rKG/strings.xml b/core/res/res/values-ky-rKG/strings.xml
index 7644a9b..4d84933 100644
--- a/core/res/res/values-ky-rKG/strings.xml
+++ b/core/res/res/values-ky-rKG/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Колдонмого камера аркылуу видео жана сүрөт тартуу уруксатын берет. Бул уруксат, камераны каалаган убакта, сиздин ырастооңузсуз колдонуу уруксатын берет."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"титирөөнү башкаруу"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Колдонмого дирилдегичти көзөмөлдөө мүмкүнчүлүгүн берет."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"кол чыракты көзөмөлдөө"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Колдонмого колчыракты көзөмөлдөө мүмкүнчүлүгүн берет."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"телефон номерлерине түз чалуу"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Колдонмого сиздин катышууңузсуз телефон номурларга чалуу уруксатын берет. Бул сиз күтпөгөн чыгымдарга же чалууларга алып келиши мүмкүн. Бул куткаруучулардын номурларына чалууга уруксат бербей тургандыгын эске алыңыз. Зыяндуу колдонмолор, сиздин ырастооңузсуз чалууларды аткарып, көп чыгымдарга себепкер болушу мүмкүн."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS чалуу кызматына мүмкүнчүлүк алуу"</string>
diff --git a/core/res/res/values-land/config.xml b/core/res/res/values-land/config.xml
new file mode 100644
index 0000000..7308dc5
--- /dev/null
+++ b/core/res/res/values-land/config.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2015 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License
+  -->
+<resources>
+    <integer name="config_dockedStackDividerSnapMode">2</integer>
+</resources>
\ No newline at end of file
diff --git a/core/res/res/values-lo-rLA/strings.xml b/core/res/res/values-lo-rLA/strings.xml
index a5ff8d1..12d67bb 100644
--- a/core/res/res/values-lo-rLA/strings.xml
+++ b/core/res/res/values-lo-rLA/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ອະນຸຍາດໃຫ້ແອັບຯຖ່າຍຮູບ ແລະວິດີໂອດ້ວຍກ້ອງຖ່າຍຮູບ. ການອະນຸຍາດນີ້ຈະອານຸຍາດໃຫ້ແອັບຯ ສາມາດໃຊ້ກ້ອງຖ່າຍຮູບໄດ້ຕະຫລອດເວລາ ໂດຍບໍ່ຕ້ອງຖ້າການຢືນຢັນຈາກທ່ານ."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ຄວບຄຸມການສັ່ນ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ອະນຸຍາດໃຫ້ແອັບຯຄວບຄຸມໂຕສັ່ນ."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ຄວບຄຸມໄຟແຟລດ"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ອະນຸຍາດໃຫ້ແອັບຯ ຄວບຄຸມໄຟແຟລດ."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ໂທຫາເບີໂທລະສັບໂດຍກົງ"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ອະນຸຍາດໃຫ້ແອັບຯໂທຫາເບີໂທລະສັບໄດ້ ໂດຍບໍ່ຕ້ອງຖ້າການດຳເນີນການໃດໆຈາກທ່ານ. ຄຸນສົມບັດນີ້ອາດກໍ່ໃຫ້ເກີດຄ່າໃຊ້ຈ່າຍໃນການໂທທີ່ບໍ່ຄາດຄິດໄດ້. ໝາຍເຫດ: ຄຸນສົມບັດນີ້ບໍ່ໄດ້ເປັນການອະນຸຍາດໃຫ້ແອັບຯ ສາມາດໂທຫາເບີສຸກເສີນ. ແອັບຯທີ່ເປັນອັນຕະລາຍອາດເຮັດໃຫ້ທ່ານ ຕ້ອງເສຍຄ່າໂທໂດຍທີ່ບໍ່ໄດ້ຄາດຄິດ."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"ເຂົ້າ​ຫາ​ການ​ບໍ​ລິ​ການ​ໂທ IMS"</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index f59e754..e35edd6 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Leidžiama programai fotografuoti ir filmuoti kamera. Šis leidimas suteikia teisę programai naudoti kamerą bet kada be jūsų patvirtinimo."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"valdyti vibraciją"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Leidžiama programai valdyti vibravimą."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"valdyti šviesos signalą"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Leidžiama programai valdyti šviesos signalą."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"skambinti tiesiogiai telefono numeriais"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Leidžiama programai skambinti telefonų numeriais be jūsų įsikišimo. Dėl to gali atsirasti nenumatytų apmokestinimų ar skambučių. Atminkite, kad programai neleidžiama skambinti pagalbos telefonų numeriais. Kenkėjiškos programos gali skambinti be jūsų patvirtinimo, o dėl to jums gali būti taikomi mokesčiai."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"pasiekti IMS skambučių paslaugą"</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index d1993ed..de02a4f 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -355,8 +355,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ļauj lietotnei uzņemt attēlus un videoklipus ar kameru. Ar šo atļauju lietotne var jebkurā brīdī izmantot kameru bez jūsu apstiprinājuma."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrolēt vibrosignālu"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ļauj lietotnei kontrolēt vibrosignālu."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolēt uzliesmojumu"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ļauj lietotnei kontrolēt zibspuldzi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"tieši zvanīt uz tālruņa numuriem"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ļauj lietotnei zvanīt uz tālruņa numuriem bez jūsu iejaukšanās. Tas var radīt neparedzētas izmaksas vai zvanus. Ņemiet vērā, ka lietotnei nav atļauts zvanīt uz tālruņa numuriem ārkārtas situācijām. Ļaunprātīgas lietotnes var radīt jums izmaksas, veicot zvanus bez jūsu apstiprinājuma."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"piekļūt tūlītējās ziņojumapmaiņas pakalpojumam, lai veiktu zvanus"</string>
diff --git a/core/res/res/values-mk-rMK/strings.xml b/core/res/res/values-mk-rMK/strings.xml
index 672c2b5..96a29a5 100644
--- a/core/res/res/values-mk-rMK/strings.xml
+++ b/core/res/res/values-mk-rMK/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Овозможува апликацијата да прави фотографии и да снима видеа со камерата. Оваа дозвола овозможува апликацијата да ја користи камерата во кое било време без ваша потврда."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контролирај вибрации"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволува апликацијата да ги контролира вибрациите."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контролирај сијаличка"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволува апликацијата да ја контролира батериската ламба."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"директно избирај телефонски броеви"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Овозможува апликацијата да повикува телефонски броеви без ваша интервенција. Ова може да предизвика неочекувани трошоци или повици. Имајте на ум дека ова не дозволува апликацијата да повикува броеви на служби за итна помош. Злонамерните апликации може да ве чинат пари поради повици без ваша потврда."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"пристапи до услугата за повици IMS"</string>
diff --git a/core/res/res/values-ml-rIN/strings.xml b/core/res/res/values-ml-rIN/strings.xml
index c6f6698..f6869e3 100644
--- a/core/res/res/values-ml-rIN/strings.xml
+++ b/core/res/res/values-ml-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ക്യാമറ ഉപയോഗിച്ച് ചിത്രങ്ങളും വീഡിയോകളും എടുക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ ഏതുസമയത്തും ക്യാമറ ഉപയോഗിക്കാൻ ഈ അനുമതി അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"വൈബ്രേറ്റുചെയ്യൽ നിയന്ത്രിക്കുക"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"വൈബ്രേറ്റർ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ടോർച്ച് നിയന്ത്രിക്കുക"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ഫ്ലാഷ്ലൈറ്റിനെ നിയന്ത്രിക്കുന്നതിന് അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ഫോൺ നമ്പറുകളിലേക്ക് നേരിട്ട് വിളിക്കുക"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"നിങ്ങളുടെ ഇടപെടൽ ഇല്ലാതെ ഫോൺ നമ്പറുകളിലേക്ക് കോൾ ചെയ്യാൻ അപ്ലിക്കേഷനെ അനുവദിക്കുന്നു. ഇത് അപ്രതീക്ഷിത നിരക്കുകൾക്കോ കോളുകൾക്കോ ഇടയാക്കാം. ഇത് അടിയന്തര നമ്പറുകളിലേക്ക് വിളിക്കാൻ അപ്ലിക്കേഷനെ അനുവദിക്കില്ലെന്ന കാര്യം ശ്രദ്ധിക്കുക. ക്ഷുദ്രകരമായ അപ്ലിക്കേഷനുകൾ നിങ്ങളുടെ സ്ഥിരീകരണമില്ലാതെ കോളുകൾ ചെയ്യുന്നത് പണച്ചെലവിനിടയാക്കാം."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS കോൾ സേവനം ആക്സസ് ചെയ്യുക"</string>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index c42beca..d982ece 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Апп нь камераар зураг авах болон видео бичих боломжтой. Энэ зөвшөөрөл нь апп-д ямар ч үед таны зөвшөөрөлгүйгээр камер ашиглах боломжийг олгоно."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"чичиргээг удирдах"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Апп нь чичиргээг удирдах боломжтой."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"гар чийдэн удирдах"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Апп нь гар чийдэнг удирдах боломжтой."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"утасны дугаарт шууд дуудлага хийх"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Апп нь таны оролцоогүйгээр дуудлага хийх боломжтой. Энэ нь төлөвлөгдөөгүй төлбөрт оруулах эсвэл дуудлага хийнэ. Энэ нь апп-г яаралтай дугаарт дуудлага хийхйг зөвшөөрөхгүй. Хортой апп нь таны зөвшөөрөлгүйгээр дуудлага хийж таныг төлбөрт оруулж болзошгүй"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS дуудлагын үйлчилгээнд хандах"</string>
diff --git a/core/res/res/values-mr-rIN/strings.xml b/core/res/res/values-mr-rIN/strings.xml
index 8bc86e6..4087199 100644
--- a/core/res/res/values-mr-rIN/strings.xml
+++ b/core/res/res/values-mr-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"कॅमेर्‍यासह चित्रे आणि व्हिडिओ घेण्यासाठी अॅप ला अनुमती देते. ही परवानगी आपल्या पुष्टीकरणाशिवाय कोणत्याही वेळी कॅमेरा वापरण्यासाठी अॅप ला परवानगी देते."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"कंपन नियंत्रित करा"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"अॅप ला व्हायब्रेटर नियंत्रित करण्यासाठी अनुमती देते."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"फ्लॅशलाइट नियंत्रित करा"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्लॅशलाइट नियंत्रित करण्यासाठी अॅप ला अनुमती देते."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नंबरवर प्रत्यक्ष कॉल करा"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"आपल्या हस्तक्षेपाशिवाय फोन नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देते. यामुळे अनपेक्षित शुल्क किंवा कॉल लागू शकतात. लक्षात ठेवा की हे आणीबाणीच्या नंबरवर कॉल करण्यासाठी अॅप ला अनुमती देत नाही. दुर्भावनापूर्ण अॅप्स नी आपल्या पुष्टिकरणाशिवाय कॉल केल्यामुळे आपले पैसे खर्च होऊ शकतात."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कॉल सेवेमध्‍ये प्रवेश करा"</string>
diff --git a/core/res/res/values-ms-rMY/strings.xml b/core/res/res/values-ms-rMY/strings.xml
index f1249d6..0923e91 100644
--- a/core/res/res/values-ms-rMY/strings.xml
+++ b/core/res/res/values-ms-rMY/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Membenarkan apl mengambil gambar dan video menggunakan kamera. Kebenaran ini membenarkan apl untuk menggunakan kamera pada bila-bila masa tanpa pengesahan anda."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kawal getaran"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Membenarkan apl mengawal penggetar."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"mengawal lampu suluh"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Membenarkan apl mengawal lampu suluh."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"panggil terus nombor telefon"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Membenarkan apl memanggil nombor telefon tanpa campur tangan anda. Ini mungkin menyebabkan caj atau panggilan yang di luar jangkaan. Apl hasad boleh menyebabkan anda kerugian wang dengan membuat panggilan tanpa pengesahan anda."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"akses perkhidmatan panggilan IMS"</string>
diff --git a/core/res/res/values-my-rMM/strings.xml b/core/res/res/values-my-rMM/strings.xml
index 3393e12..3ef7e6c 100644
--- a/core/res/res/values-my-rMM/strings.xml
+++ b/core/res/res/values-my-rMM/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"အပလီကေးရှင်းအား အလိုအလျောက် ဓာတ်ပုံရိုက်ခွင့်၊ ဗီဒီယို ရိုက်ကူးခွင့် ပြုပါ။ ဒီခွင့်ပြုချက်က အပလီကေးရှင်းကို အချိန်မရွေး ကင်မရာအား ခွင့်ပြုချက် မလိုအပ်ပဲ သုံးခွင့်ပြုပါသည်။"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"တုန်ခုန်မှုအား ထိန်းချုပ်ခြင်း"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"appအား တုန်ခါစက်ကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ဓါတ်မီးအား ထိန်းသိမ်းရန်"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"appအား ကား ဖလက်ရှမီးကို ထိန်းချုပ်ခွင့် ပြုသည်။"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ဖုန်းနံပါတ်များကိုတိုက်ရိုက်ခေါ်ဆိုခြင်း"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"အပလီကေးရှင်းအား အလိုအလျောက် ဖုန်းခေါ်ခွင့် ပြုပါ။ မလိုအပ်သော ဖုန်းခ များ ဖြစ်ပေါ်နိုင်ပါသည်။ ဒီခွင့်ပြုခြင်းမှာ အရေးပေါ်ဖုန်းခေါ်ခြင်း မပါဝင်ပါ။ သံသယဖြစ်စရာ အပလီကေးရှင်းများက သင့်မသိပဲ ဖုန်းခေါ်ခြင်းဖြင့် ဖုန်းခ ပိုမိုကျနိုင်ပါသည်။"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ဖုန်းခေါ်ဆိုမှု ဝန်ဆောင်ဌာန ဝင်ကြည့်ပါ"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index e1ad565..cd65d85 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Appen tillates å ta bilder og filme med kameraet. Det betyr at appen kan bruke kameraet når som helst uten bekreftelse fra deg."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollere vibreringen"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Lar appen kontrollere vibreringsfunksjonen."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollere lommelykten"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Lar appen kontrollere lommelykten."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ringe telefonnummer direkte"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Lar appen ringe telefonnumre uten at du gjør noe. Dette kan resultere i uventede oppringninger og kostnader. Appen kan imidlertid ikke ringe nødnumre. Merk at skadelige apper kan påføre deg kostnader ved å ringe uten bekreftelse fra deg."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"få tilgang til nettprattjenesten for ringing"</string>
diff --git a/core/res/res/values-ne-rNP/strings.xml b/core/res/res/values-ne-rNP/strings.xml
index f94222b..301094b 100644
--- a/core/res/res/values-ne-rNP/strings.xml
+++ b/core/res/res/values-ne-rNP/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"अनुप्रयोगलाई क्यामेरासँग तस्बिर र भिडियोहरू लिन अनुमति दिन्छ। यस अनुमतिले अनुप्रयोगलाई तपाईंको पुष्टिकरण बिना कुनै पनि समयमा क्यामेरा प्रयोग गर्न स्वीकृति दिन्छ।"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"कम्पन नियन्त्रण गर्नुहोस्"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"अनुप्रयोगलाई भाइब्रेटर नियन्त्रण गर्न अनुमति दिन्छ।"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"फ्ल्यासलाईट नियन्त्रण गर्नुहोस्"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"फ्ल्यास प्रकाशलाई नियन्त्रण गर्न अनुप्रयोगलाई अनुमति दिन्छ।"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"फोन नम्बरहरूमा सिधै कल गर्नुहोस्"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"तपाईँको हस्तक्षेप बेगरै फोन नम्बर कल गर्न अनुप्रयोगलाई अनुमति दिन्छ। यसले अनपेक्षित शुल्क वा कलहरू गराउन सक्छ। यसले अनुप्रयोगलाई आपतकालीन नम्बरहरू कल गर्न अनुमति दिँदैन विचार गर्नुहोस्। खराब अनुप्रयोगहरूले तपाईँको स्वीकार बिना कलहरू गरेर तपाईँलाई बढी पैसा तिराउन सक्छ।"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS कल सेवा पहुँच गर्नुहोस्"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index 1bef95d..1407991 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Hiermee kan de app foto\'s en video\'s maken met de camera. Met deze toestemming kan de app de camera altijd gebruiken, zonder je bevestiging."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"trilling beheren"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Hiermee kan de app de trilstand beheren."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"zaklamp bedienen"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Hiermee kan de app de zaklamp bedienen."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefoonnummers rechtstreeks bellen"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Hiermee kan de app zonder je tussenkomst telefoonnummers bellen. Dit kan tot onverwachte kosten of oproepen leiden. De app kan hiermee geen noodnummers bellen. Schadelijke apps kunnen u geld kosten door nummers te bellen zonder om je bevestiging te vragen."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"toegang tot IMS-service voor bellen"</string>
diff --git a/core/res/res/values-pa-rIN/strings.xml b/core/res/res/values-pa-rIN/strings.xml
index 168c66f..39f20f5 100644
--- a/core/res/res/values-pa-rIN/strings.xml
+++ b/core/res/res/values-pa-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ਐਪ ਨੂੰ ਕੈਮਰੇ ਨਾਲ ਤਸਵੀਰਾਂ ਅਤੇ ਵੀਡੀਓ ਲੈਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਹ ਅਨੁਮਤੀ ਐਪ ਨੂੰ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਿਸੇ ਵੀ ਸਮੇਂ ਕੈਮਰਾ ਵਰਤਣ ਦੀ ਆਗਿਆ ਦਿੰਦੀ ਹੈ।"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ਵਾਈਬ੍ਰੇਸ਼ਨ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ਐਪ ਨੂੰ ਵਾਈਬ੍ਰੇਟਰ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਓ"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ਐਪ ਨੂੰ ਫਲੈਸ਼ਲਾਈਟ ਤੇ ਨਿਯੰਤਰਣ ਪਾਉਣ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ।"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਸਿੱਧੇ ਕਾਲ ਕਰੋ"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ਐਪ ਨੂੰ ਤੁਹਾਡੇ ਦਖ਼ਲ ਤੋਂ ਬਿਨਾਂ ਫੋਨ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਦਿੰਦਾ ਹੈ। ਇਸਦੇ ਸਿੱਟੇ ਵਜੋਂ ਅਕਲਪਿਤ ਖ਼ਰਚੇ ਜਾਂ ਕਾਲਾਂ ਹੋ ਸਕਦੀਆਂ ਹਨ। ਧਿਆਨ ਦਿਓ ਕਿ ਇਹ ਐਪ ਨੂੰ ਐਮਰਜੈਂਸੀ ਨੰਬਰਾਂ ਤੇ ਕਾਲ ਕਰਨ ਦੀ ਆਗਿਆ ਨਹੀਂ ਦਿੰਦਾ। ਖ਼ਰਾਬ ਐਪਸ ਤੁਹਾਡੀ ਪੁਸ਼ਟੀ ਤੋਂ ਬਿਨਾਂ ਕਾਲਾਂ ਕਰਕੇ ਤੁਹਾਨੂੰ ਖ਼ਰਚੇ ਪਾ ਸਕਦੇ ਹਨ।"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ਕਾਲ ਸੇਵਾ ਤੱਕ ਪਹੁੰਚ"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 80ef7df..f3e50b5 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Pozwala aplikacji na robienie zdjęć i nagrywanie filmów przy użyciu aparatu. Aplikacja z tym uprawnieniem może użyć aparatu w dowolnym momencie bez Twojego potwierdzenia."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"sterowanie wibracjami"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Pozwala aplikacji na sterowanie wibracjami."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolowanie latarki"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Pozwala aplikacji na sterowanie latarką."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"bezpośrednie wybieranie numerów telefonów"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Pozwala aplikacji na dzwonienie pod numery telefonów bez Twojej wiedzy. Może to skutkować nieoczekiwanymi opłatami lub połączeniami. Aplikacja nie może dzwonić pod numery alarmowe. Złośliwe aplikacje mogą generować koszty, wykonując połączenia bez Twojego potwierdzenia."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"usługa telefoniczna z dostępem do komunikatora"</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index 11e060a..89bbbe8 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index d76133a..f559dbb 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que a aplicação tire fotografias e grave vídeos com a câmara. Esta autorização permite que a aplicação utilize a câmara sem a sua confirmação em qualquer altura."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite à aplicação controlar o vibrador."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite à aplicação controlar a lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"marcar números de telefone diretamente"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que a aplicação ligue para números de telefone sem a intervenção do utilizador. Esta ação pode resultar em cobranças ou chamadas inesperadas. Tenha em atenção que isto não permite que a aplicação ligue para números de emergência. As aplicações maliciosas podem fazer com que incorra em custos, fazendo chamadas sem a sua confirmação."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"aceder ao serviço de chamadas IMS"</string>
@@ -1478,7 +1476,7 @@
       <item quantity="one">Durante 1 h</item>
     </plurals>
     <string name="zen_mode_until" msgid="7336308492289875088">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g>"</string>
-    <string name="zen_mode_alarm" msgid="9128205721301330797">"Até às <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
+    <string name="zen_mode_alarm" msgid="9128205721301330797">"Até <xliff:g id="FORMATTEDTIME">%1$s</xliff:g> (próximo alarme)"</string>
     <string name="zen_mode_forever" msgid="7420011936770086993">"Até que o utilizador desative"</string>
     <string name="zen_mode_forever_dnd" msgid="3792132696572189081">"Até desativar Não incomodar"</string>
     <string name="zen_mode_rule_name_combination" msgid="191109939968076477">"<xliff:g id="FIRST">%1$s</xliff:g>/<xliff:g id="REST">%2$s</xliff:g>"</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index 11e060a..89bbbe8 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite que o app tire fotos e filme vídeos com a câmera. Esta permissão autoriza o app a usar a câmera a qualquer momento sem sua confirmação."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlar vibração"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite que o app controle a vibração."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"controlar lanterna"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite que o app controle a lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ligar diretamente para números de telefone"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite que o app ligue para números de telefone sem sua intervenção. Isso pode resultar em cobranças ou chamadas inesperadas. Esta opção não permite que o app ligue para números de emergência. Apps maliciosos podem gerar custos com chamadas feitas sem sua confirmação."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"acessar serviço de mensagens instantâneas para chamadas"</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index 8a78f17..4086e69 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -355,8 +355,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Permite aplicației să realizeze fotografii și videoclipuri cu camera foto. Cu această permisiune aplicația utilizează camera foto oricând și fără confirmare."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"controlează vibrarea"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Permite aplicației să controleze mecanismul de vibrare."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"control lanternă"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Permite aplicației să controleze lanterna."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"apelare directă numere de telefon"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Permite aplicației să apeleze numere de telefon fără intervenţia dvs. Acest lucru poate determina apariția unor taxe sau a unor apeluri neaşteptate. Cu această permisiune aplicația nu poate apela numerele de urgenţă. Aplicaţiile rău intenţionate pot acumula costuri prin efectuarea unor apeluri fără confirmare."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"accesează serviciul de apelare IMS"</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index 0753e93..ee39b83 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Приложение сможет снимать фотографии и видеоролики с помощью камеры в любое время без вашего разрешения."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"Управление функцией вибросигнала"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Приложение сможет контролировать вибросигналы."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"Управление вспышкой"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Приложение сможет контролировать вспышку."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"Осуществление телефонных вызовов"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Приложение сможет без вашего участия звонить на любой номер телефона. Это не относится к номерам экстренных служб. Вредоносные программы смогут совершать вызовы без вашего разрешения, что может привести к непредвиденным расходам."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"совершение звонков с помощью службы IMS"</string>
diff --git a/core/res/res/values-si-rLK/strings.xml b/core/res/res/values-si-rLK/strings.xml
index d66b245..5364c98 100644
--- a/core/res/res/values-si-rLK/strings.xml
+++ b/core/res/res/values-si-rLK/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"කැමරාවෙන් පින්තූර ගැනීමට සහ වීඩියෝ කිරීමට යෙදුමට අවසර දෙන්න. මෙම අවසරය මඟින් ඔබගේ අනුදැනුමකින් තොරව ඕනෑම වේලාවකදී කැමරාව භාවිතා කිරීමට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"කම්පනය පාලනය කිරීම"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"කම්පකය පාලනයට යෙදුමට අවසර දෙන්න."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"සැණෙළි ආලෝකය පාලනය කරන්න"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"සැණෙළිය පාලනයට යෙදුමට අවසර දෙන්න."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"දුරකථන අංක වෙත ඍජුවම අමතන්න"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ඔබගේ මැදිහත් වීමක් නොමැතිව දුරකථන අංක ඇමතීමට යෙදුමට අවසර දෙන්න. මෙහි ප්‍රතිඑලය වන්නේ අනපේක්ෂිත අයකිරීම් හෝ ඇමතුම් ඇතිවීමයි. මෙයන් හදිසි අංක වලට ඇමතුම් ගැනීමට යෙදුමට අවසර නොදෙන බවට සටහන් කරගන්න. ඔබගේ අනුදැනුමක් නොමැතිව ඇමතුම් ගැනීමෙන් අනිෂ්ට යෙදුම් ඔබගේ මුදල් නිකරුණේ වැය කරයි."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS ඇමතුම් සේවාවට පිවිසෙන්න"</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 05c8467..90ccd54 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Umožňuje aplikácii fotografovať a nahrávať videá pomocou fotoaparátu. Toto povolenie umožňuje aplikácii používať fotoaparát kedykoľvek a bez vášho potvrdenia."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ovládať vibrovanie"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Umožňuje aplikácii ovládať vibrácie."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ovládať kontrolku"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Umožňuje aplikácii ovládať svetlo."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"priamo volať na telefónne čísla"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Umožňuje aplikácii volať telefónne čísla bez vášho zásahu. V dôsledku toho sa môžu účtovať neočakávané poplatky alebo sa môžu uskutočniť neočakávané hovory. Toto povolenie neumožňuje aplikácii volať na čísla tiesňového volania."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"prístup k službe volania IMS"</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index ea5f4c4..4e9b1c5 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Aplikaciji omogoča fotografiranje in snemanje videoposnetkov s kamero. S tem dovoljenjem lahko aplikacija kadar koli uporablja kamero brez vaše potrditve."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"nadzor vibriranja"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Aplikaciji omogoča nadzor vibriranja."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"nadzor svetilke"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Aplikaciji omogoča nadzor svetilke."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"neposredno klicanje telefonskih številk"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Aplikaciji omogoča klicanje telefonskih številk brez vašega posredovanja. Zaradi tega lahko pride do nepričakovanih stroškov ali klicev. Aplikaciji to ne dovoljuje opravljanja klicev v sili. Zlonamerne aplikacije lahko kličejo brez vaše potrditve, kar vas lahko drago stane."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"dostop do storitve za klicanje IMS"</string>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 77e0e62..be9c709 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Lejon aplikacion të krijojë fotografi dhe video me kamerën. Kjo leje mundëson përdorimin e kamerës në çdo kohë pa konfirmimin tënd."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrollo dridhjen"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Lejon aplikacionin të kontrollojë dridhësin."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrollo elektrikun"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Lejon aplikacionin të kontrollojë elektrikun."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefono drejtpërdrejt numrat e telefonit"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Lejon aplikacionin të telefonojë numra pa ndërhyrjen tënde. Kjo mund të rezultojë në tarifa ose telefonata të papritura. Ki parasysh se kjo nuk e lejon aplikacionin të telefonojë numra urgjence. Aplikacione keqdashëse mund të të kushtojnë para duke kryer telefonata pa konfirmimin tënd."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"qasje në shërbimin e telefonatave IMS"</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 2423418..a3618ab 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -355,8 +355,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Дозвољава апликацији да снима слике и видео снимке камером. Ова дозвола омогућава апликацији да у било ком тренутку користи камеру без ваше потврде."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контрола вибрације"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозвољава апликацији да контролише вибрацију."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контрола осветљења"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозвољава апликацији да контролише блиц."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"директно позивање бројева телефона"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Дозвољава апликацији да позива бројеве телефона без ваше дозволе. Ово може да доведе до неочекиваних трошкова или позива. Имајте на уму да ово не дозвољава апликацији да позива бројеве за хитне случајеве. Злонамерне апликације могу да позивају без ваше потврде, што може да доведе до трошкова."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"приступ услузи позива помоћу размене тренутних порука"</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index cdf252e..b07dc28 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Tillåter att appen tar bilder och spelar in videor med kameran. Med den här behörigheten tillåts appen att använda kameran när som helst utan ditt godkännande."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"styra vibration"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Tillåter att appen styr vibrationen."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"styra lampa"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Tillåter att appen styr lampan."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ringa telefonnummer direkt"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Tillåter att appen ringer telefonnummer utan någon aktiv åtgärd från dig. Detta kan leda till oväntade avgifter och samtal. Observera att appen inte tillåts ringa nödsamtal. Skadliga appar kan ringa utan ditt godkännande och detta kan kosta pengar."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"tillgång till tjänsten för snabbmeddelanden vid samtal"</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 5e618bf..cf0063c 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Inaruhusu programu kupiga picha na video kwa kamera. Kibali hiki kinaruhusu programu kutumia kamera kwa wakati wowote bila uthibitisho wako."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"Kudhibiti mtetemo"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Inaruhusu programu kudhibiti kitingishi."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"dhibiti tochi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Inaruhusu programu kudhibiti tochi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"piga simu moja kwa moja kwa nambari za simu"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Inaruhusu programu kupiga nambari za simu bila ya wewe kuingilia kati. Hii inaweza kusababisha gharama zisizotarajiwa au simu. Kumbuka kuwa hii hairuhusu programu kupiga nambari za dharura. Programu hasidi zinaweza kukugharimu pesa kwa kupiga simu bila uthibitisho wako."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"fikia huduma ya simu ya IMS"</string>
@@ -795,7 +793,7 @@
     <string name="save_password_remember" msgid="6491879678996749466">"Kumbuka"</string>
     <string name="save_password_never" msgid="8274330296785855105">"Katu"</string>
     <string name="open_permission_deny" msgid="7374036708316629800">"Hauna idhini ya kufungua ukurasa huu."</string>
-    <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao klipu."</string>
+    <string name="text_copied" msgid="4985729524670131385">"Maandishi yamenakiliwa kwenye ubao wa kunakili."</string>
     <string name="more_item_label" msgid="4650918923083320495">"Zaidi"</string>
     <string name="prepend_shortcut_label" msgid="2572214461676015642">"Menyu+"</string>
     <string name="menu_space_shortcut_label" msgid="2410328639272162537">"mwanya"</string>
diff --git a/core/res/res/values-sw600dp/config.xml b/core/res/res/values-sw600dp/config.xml
index 5a007ce..7f57ded 100644
--- a/core/res/res/values-sw600dp/config.xml
+++ b/core/res/res/values-sw600dp/config.xml
@@ -40,5 +40,6 @@
     <!-- Use a larger scaling span for larger screen devices. -->
     <dimen name="config_minScalingSpan">32mm</dimen>
 
+    <integer name="config_dockedStackDividerSnapMode">1</integer>
 </resources>
 
diff --git a/core/res/res/values-ta-rIN/strings.xml b/core/res/res/values-ta-rIN/strings.xml
index 7e0ab5e..ecefb77 100644
--- a/core/res/res/values-ta-rIN/strings.xml
+++ b/core/res/res/values-ta-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"கேமரா மூலமாகப் படங்களையும், வீடியோக்களையும் எடுக்க பயன்பாட்டை அனுமதிக்கிறது. உங்கள் உறுதிப்படுத்தல் இன்றி கேமராவை எந்நேரத்திலும் பயன்படுத்தப் பயன்பாட்டை இது அனுமதிக்கிறது."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"அதிர்வைக் கட்டுப்படுத்துதல்"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"அதிர்வைக் கட்டுப்படுத்தப் பயன்பாட்டை அனுமதிக்கிறது."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ஃப்லாஷ்லைட்டை இயக்குதல்"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ஃப்ளாஷ் லைட்டைக் கட்டுப்படுத்த, பயன்பாட்டை அனுமதிக்கிறது."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"தொலைபேசி எண்களை நேரடியாக அழைத்தல்"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"உங்கள் தலையீட்டின்றி மொபைல் எண்களை அழைக்கப் பயன்பாட்டை அனுமதிக்கிறது. இதன் விளைவாக எதிர்பாராத கட்டணங்களோ அழைப்புகளோ ஏற்படலாம். அவசரகால எண்களை அழைக்க இது பயன்பாட்டை அனுமதிக்காது என்பதை நினைவில்கொள்ளவும். தீங்கிழைக்கும் பயன்பாடுகள், உங்கள் உறுதிப்படுத்தல் இன்றி அழைப்புகளைச் செய்வதால் உங்களுக்குச் செலவு ஏற்படக்கூடும்."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS அழைப்புச் சேவையை அணுகுதல்"</string>
diff --git a/core/res/res/values-te-rIN/strings.xml b/core/res/res/values-te-rIN/strings.xml
index 87b782f..b1bccd2 100644
--- a/core/res/res/values-te-rIN/strings.xml
+++ b/core/res/res/values-te-rIN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"కెమెరాతో చిత్రాలు మరియు వీడియోలను తీయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. ఈ అనుమతి మీ నిర్ధారణ లేకుండానే ఎప్పుడైనా కెమెరాను ఉపయోగించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"వైబ్రేషన్‌ను నియంత్రించడం"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"వైబ్రేటర్‌ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ఫ్లాష్‌కాంతిని నియంత్రించడం"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ఫ్లాష్‌లైట్‌ను నియంత్రించడానికి అనువర్తనాన్ని అనుమతిస్తుంది."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ఫోన్ నంబర్‌లకు నేరుగా కాల్ చేయడం"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"మీ ప్రమేయం లేకుండా ఫోన్ నంబర్‌లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతిస్తుంది. దీని వలన అనుకోని ఛార్జీలు విధించబడవచ్చు లేదా కాల్‌లు రావచ్చు. ఇది అత్యవసర నంబర్‌లకు కాల్ చేయడానికి అనువర్తనాన్ని అనుమతించదని గుర్తుంచుకోండి. హానికరమైన అనువర్తనాలు మీ నిర్ధారణ లేకుండానే కాల్‌లు చేయడం ద్వారా మీకు డబ్బు ఖర్చయ్యేలా చేయవచ్చు."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS కాల్ సేవ ప్రాప్యత అనుమతి"</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index 2ec0f4c..0b8e60d 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"อนุญาตให้แอปพลิเคชันถ่ายภาพและวิดีโอด้วยกล้องถ่ายรูปนี้ การอนุญาตนี้จะทำให้แอปพลิเคชันสามารถใช้กล้องถ่ายรูปได้ทุกเมื่อโดยไม่ต้องรอการยืนยันจากคุณ"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ควบคุมการสั่นเตือน"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"อนุญาตให้แอปพลิเคชันควบคุมการสั่นเตือน"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"ควบคุมไฟฉาย"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"อนุญาตให้แอปพลิเคชันควบคุมไฟฉาย"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"โทรติดต่อหมายเลขโทรศัพท์โดยตรง"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"อนุญาตให้แอปพลิเคชันโทรเข้าโทรศัพท์โดยไม่ต้องให้คุณจัดการ ซึ่งอาจทำให้มีการเรียกเก็บเงินหรือการโทรที่ไม่คาดคิด โปรดทราบว่าการทำงานนี้ไม่ได้อนุญาตให้แอปพลิเคชันโทรไปหมายเลขฉุกเฉิน แอปพลิเคชันที่เป็นอันตรายอาจทำให้คุณต้องเสียค่าบริการด้วยการโทรโดยไม่ขอการยืนยันจากคุณ"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"เข้าถึงบริการโทร IMS"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 36aa9d9..02a3587 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Pinapayagan ang app na kumuha ng mga larawan at video gamit ang camera. Pinapayagan ng pahintulot na ito ang app na gamitin ang camera anumang oras nang wala ng iyong kumpirmasyon."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kontrolin ang pag-vibrate"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Pinapayagan ang app na kontrolin ang vibrator."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kontrolin ang flashlight"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Pinapayagan ang app na kontrolin ang flashlight."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"direktang tawagan ang mga numero ng telepono"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Pinapayagan ang app na tumawag sa mga numero ng telepono nang wala ng iyong panghihimasok. Maaari itong magresulta sa mga hindi inaasahang pagsingil o tawag. Tandaan na hindi nito pinapayagan ang app na tumawag sa mga numerong pang-emergency. Maaaring magpagastos sa iyo ng pera ang nakakahamak na apps sa pamamagitan ng pagtawag nang wala ng iyong kumpirmasyon."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"i-access ang serbisyo sa tawag ng IMS"</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 7b0bdc6..283bcebb 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Uygulamaya kamerayla fotoğraf ve video çekme izni verir. Bu izin, uygulamanın sizin onayınız olmadan istediği zaman kamerayı kullanmasına olanak sağlar."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"titreşimi denetleme"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Uygulamaya, titreşimi denetleme izni verir."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"el fenerini denetle"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Uygulamaya, el fenerini denetleme izni verir."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon numaralarına doğrudan çağrı yap"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Uygulamaya sizin müdahaleniz olmadan telefon numaralarına çağrı yapma izni verir. Bu durum beklenmeyen ödemelere veya çağrılara neden olabilir. Ancak bu iznin, uygulamanın acil numaralara çağrı yapmasına olanak sağlamadığını unutmayın. Kötü amaçlı uygulamalar onayınız olmadan çağrılar yaparak sizi zarara sokabilir."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS çağrı hizmetine erişme"</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 308e50c..fce4cc3 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -356,8 +356,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Дозволяє програмі фотографувати та знімати відео за допомогою камери. Такий дозвіл дає програмі змогу будь-коли використовувати камеру без вашого підтвердження."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"контролювати вібросигнал"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Дозволяє програмі контролювати вібросигнал."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"контр. блим. світло"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Дозволяє програмі контролювати світловий сигнал."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"прямо набирати номери тел."</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Дозволяє програмі набирати номери телефону без вашого відома. Це може спричинити неочікуване стягнення плати чи здійснення дзвінків. Зауважте, що це не дозволяє програмі набирати екстрені номери. Шкідливі програми можуть здійснювати дзвінки без вашого підтвердження, за що з вас стягуватимуться кошти."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"отримувати доступ до телефонної служби IMS"</string>
diff --git a/core/res/res/values-ur-rPK/strings.xml b/core/res/res/values-ur-rPK/strings.xml
index ca26e9b..519f42b 100644
--- a/core/res/res/values-ur-rPK/strings.xml
+++ b/core/res/res/values-ur-rPK/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"ایپ کو کیمرے سے تصویریں لینے اور ویڈیوز بنانے کی اجازت دیتا ہے۔ یہ اجازت ایپ کو آپ کی تصدیق کے بغیر کسی بھی وقت کیمرا استعمال کرنے کی اجازت دیتی ہے۔"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"ارتعاش کو کنٹرول کریں"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"ایپ کو وائبریٹر کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"فلیش لائٹ کنٹرول"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"ایپ کو فلیش لائٹ کنٹرول کرنے کی اجازت دیتا ہے۔"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"براہ راست فون نمبرز پر کال کریں"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"ایپ کو آپ کی مداخلت کے بغیر فون نمبروں پر کال کرنے کی اجازت دیتا ہے۔ اس کے نتیجے میں غیر متوقع چارجز یا کالیں ہوسکتی ہیں۔ نوٹ کرلیں کہ یہ ایپ کو ہنگامی نمبروں پر کال کرنے کی اجازت نہیں دیتا ہے۔ نقصان دہ ایپس آپ کی تصدیق کے بغیر کالیں کرکے آپ کی رقم صرف کروا سکتے ہیں۔"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"‏IMS کال سروس تک رسائی حاصل کریں"</string>
diff --git a/core/res/res/values-uz-rUZ/strings.xml b/core/res/res/values-uz-rUZ/strings.xml
index 3f3d151..e90d921 100644
--- a/core/res/res/values-uz-rUZ/strings.xml
+++ b/core/res/res/values-uz-rUZ/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ilovaga kameradan foydalanib rasm va videoga olishga ruxsat beradi. Bu ruxsat ilovaga sizdan tasdiqlashni so‘ramasdan kameradan foydalanishga imkon beradi."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"tebranishni boshqarish"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ilova tebranishli signallarni boshqarishi mumkin."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"chiroq chaqnashini boshqarish"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ilova chaqnoqni boshqarishi mumkin."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"telefon raqamlariga tog‘ridan to‘g‘ri qo‘ng‘iroq qilish"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ilovaga sizning yordamingizsiz telefonga qo‘ng‘iroq qilish imkonini beradi. Bu kutilmagan qo‘ng‘iroqlarni amalga oshirishi yoki ortiqcha to‘lovlarni yuzaga keltirishi mumkin. Shunga e’tibor qilinki, u favqulodda telefon raqamlariga qo‘ng‘iroqlar qilishga ruxsat bermaydi. Zararli ilovalar sizdan so‘ramasdan qo‘ng‘iroqlarni amalga oshirib, pulingizni sarflashi mumkin."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"IMS qo‘ng‘iroq xizmatiga kirish"</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index c538684..31e090b 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Cho phép ứng dụng chụp ảnh và quay video bằng máy ảnh. Quyền này cho phép ứng dụng sử dụng máy ảnh bất kỳ lúc nào mà không cần sự xác nhận của bạn."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"kiểm soát rung"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Cho phép ứng dụng kiểm soát bộ rung."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"kiểm soát đèn nháy"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Cho phép ứng dụng kiểm soát đèn nháy."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"gọi trực tiếp số điện thoại"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Cho phép ứng dụng gọi các số điện thoại mà không cần sự can thiệp của bạn. Việc này có thể dẫn đến các khoản phí hoặc cuộc gọi không mong muốn. Lưu ý rằng quyền này không cho phép ứng dụng gọi các số khẩn cấp. Các ứng dụng độc hại có thể khiến bạn tốn tiền do thực hiện cuộc gọi mà không cần sự xác nhận của bạn."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"truy cập dịch vụ gọi điện qua IMS"</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index 77053f2..c5cd59a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允许该应用使用相机拍摄照片和视频。此权限可让该应用随时使用相机,而无需您的确认。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制振动"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"允许应用控制振动器。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"控制闪光灯"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"允许应用控制闪光灯。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接拨打电话号码"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"允许该应用在您未执行操作的情况下拨打电话号码。此权限可能会导致意外收费或呼叫。请注意,此权限不允许该应用拨打紧急电话号码。恶意应用可通过拨打电话产生相关费用,而无需您的确认。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用即时通讯通话服务"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 612efe4..36ba2ad6 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限允許應用程式隨時使用相機,而不需經您確認。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式繞過您自行撥打電話號碼,但可能會產生未預期的費用或撥打未預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能未經您確認擅自撥打電話,增加您的支出。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"使用 IMS 通話服務"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 201cc1e..72ea523 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"允許應用程式使用相機拍照和錄影。這項權限可讓應用程式隨時使用相機,而不需請求您進行確認。"</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"控制震動"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"允許應用程式控制震動。"</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"控制閃光燈"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"允許應用程式控制閃光燈。"</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"直接撥打電話號碼"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"允許應用程式自行撥打電話,但可能產生非預期的費用或撥打非預期的電話。注意:這項權限不允許應用程式撥打緊急電話。惡意應用程式可能利用此功能擅自撥打電話,增加您不必要的額外支出。"</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"存取 IMS 撥號服務"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index 5e835e3..bee7eea 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -354,8 +354,6 @@
     <string name="permdesc_camera" msgid="8497216524735535009">"Ivumela uhlelo lokusebenza ukuthatha izithombe namavidiyo ngekhamera. Le mvume ivumela uhlelo lokusebenza ukusebenzisa ikhamera nganoma isiphi isikhathi ngaphandle kwemvume yakho."</string>
     <string name="permlab_vibrate" msgid="7696427026057705834">"lawula ukudlidliza"</string>
     <string name="permdesc_vibrate" msgid="6284989245902300945">"Ivumela uhlelo lokusebenza ukulawula isidlidlizi."</string>
-    <string name="permlab_flashlight" msgid="2155920810121984215">"lawula ukukhanya kwefulashi"</string>
-    <string name="permdesc_flashlight" msgid="6522284794568368310">"Ivumela uhlelo lokusebenza ukulawula ukukhanya kwefuleshi."</string>
     <string name="permlab_callPhone" msgid="3925836347681847954">"ngokuqondile shayela izinombolo zocingo"</string>
     <string name="permdesc_callPhone" msgid="3740797576113760827">"Ivumela uhlelo lokusebenza ukushayela izinombolo zefoni ngaphandle kokuhlanganyela kwakho. Lokhu kungaholela emashajini noma amakholi angalindelekile. Qaphela ukuthi lokhu akuvumeli uhlelo lokusebenza ukushayela izinombolo zesimo esiphuthumayo. Izinhlelo zokusebenza ezingalungile zingabiza imali ngokwenze amakholi ngaphandle kokuqinisekisa kwakho."</string>
     <string name="permlab_accessImsCallService" msgid="3574943847181793918">"finyelela kusevisi yekholi ye-IMS"</string>
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 2a11081..58a77e8 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1857,6 +1857,11 @@
         <attr name="lockTaskMode" />
         <attr name="showForAllUsers" />
         <attr name="encryptionAware" />
+        <!-- @hide This activity is always focusable regardless of if it is in a task/stack whose
+             activities are normally not focusable.
+             For example, {@link android.R.attr#supportsPictureInPicture} activities are placed
+             in a task/stack that isn't focusable. This flag allows them to be focusable.-->
+        <attr name="alwaysFocusable" format="boolean" />
     </declare-styleable>
 
     <!-- The <code>activity-alias</code> tag declares a new
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index c03d471..d13a622 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2410,4 +2410,11 @@
 
     <!-- Default bounds [left top right bottom] on screen for picture-in-picture windows. -->
     <string translatable="false" name="config_defaultPictureInPictureBounds">"0 0 100 100"</string>
+
+    <!-- Controls the snap mode for the docked stack divider
+             0 - 3 snap targets: left/top has 16:9 ratio, 1:1, and right/bottom has 16:9 ratio
+             1 - 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+             2 - 1 snap target: 1:1
+    -->
+    <integer name="config_dockedStackDividerSnapMode">0</integer>
 </resources>
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index ef6b467..37b2c12 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -429,4 +429,6 @@
 
     <item type="dimen" format="integer" name="time_picker_column_start_material">0</item>
     <item type="dimen" format="integer" name="time_picker_column_end_material">1</item>
+
+    <item type="fraction" name="docked_stack_divider_fixed_ratio">34.15%</item>
 </resources>
diff --git a/core/res/res/values/locale_config.xml b/core/res/res/values/locale_config.xml
index eee5771..3cfd9f4 100644
--- a/core/res/res/values/locale_config.xml
+++ b/core/res/res/values/locale_config.xml
@@ -49,6 +49,7 @@
         <item>ar-SY</item> <!-- Arabic (Syria) -->
         <item>ar-TD</item> <!-- Arabic (Chad) -->
         <item>ar-TN</item> <!-- Arabic (Tunisia) -->
+        <item>ar-XB</item> <!-- Right-to-left pseudolocale -->
         <item>ar-YE</item> <!-- Arabic (Yemen) -->
         <item>as-IN</item> <!-- Assamese (India) -->
         <item>asa-TZ</item> <!-- Asu (Tanzania) -->
@@ -195,6 +196,7 @@
         <item>en-VI</item> <!-- English (U.S. Virgin Islands) -->
         <item>en-VU</item> <!-- English (Vanuatu) -->
         <item>en-WS</item> <!-- English (Samoa) -->
+        <item>en-XA</item> <!-- Left-to-right pseudolocale -->
         <item>en-ZA</item> <!-- English (South Africa) -->
         <item>en-ZM</item> <!-- English (Zambia) -->
         <item>en-ZW</item> <!-- English (Zimbabwe) -->
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 347f2f9..be9ba62 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1026,11 +1026,6 @@
     <string name="permdesc_vibrate">Allows the app to control the vibrator.</string>
 
     <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permlab_flashlight">control flashlight</string>
-    <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
-    <string name="permdesc_flashlight">Allows the app to control the flashlight.</string>
-
-    <!-- Title of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permlab_callPhone">directly call phone numbers</string>
     <!-- Description of an application permission, listed so the user can choose whether they want to allow the application to do this. -->
     <string name="permdesc_callPhone">Allows the app to call phone numbers
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 3c1d944..845c8c9 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1492,6 +1492,8 @@
   <java-symbol type="bool" name="target_honeycomb_needs_options_menu" />
   <java-symbol type="dimen" name="docked_stack_divider_thickness" />
   <java-symbol type="dimen" name="docked_stack_divider_insets" />
+  <java-symbol type="integer" name="config_dockedStackDividerSnapMode" />
+  <java-symbol type="fraction" name="docked_stack_divider_fixed_ratio" />
   <java-symbol type="dimen" name="navigation_bar_height" />
   <java-symbol type="dimen" name="navigation_bar_height_landscape" />
   <java-symbol type="dimen" name="navigation_bar_width" />
diff --git a/core/tests/coretests/Android.mk b/core/tests/coretests/Android.mk
index 7cd25af..ee8921e 100644
--- a/core/tests/coretests/Android.mk
+++ b/core/tests/coretests/Android.mk
@@ -22,7 +22,7 @@
 	$(call all-java-files-under, EnabledTestApp/src)
 
 LOCAL_DX_FLAGS := --core-library
-LOCAL_AAPT_FLAGS = -0 dat -0 gld
+LOCAL_AAPT_FLAGS = -0 dat -0 gld -c fa
 LOCAL_STATIC_JAVA_LIBRARIES := \
     core-tests-support \
     android-common \
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 5177836..c0453f8 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -146,6 +146,16 @@
             </intent-filter>
         </activity>
 
+        <activity android:name="android.widget.DatePickerActivity"
+                android:label="DatePickerActivity"
+                android:screenOrientation="portrait"
+                android:theme="@android:style/Theme.Material.Light">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.FRAMEWORK_INSTRUMENTATION_TEST" />
+            </intent-filter>
+        </activity>
+
         <activity android:name="android.widget.focus.DescendantFocusability" android:label="DescendantFocusability">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN" />
diff --git a/core/tests/coretests/res/layout/datepicker_layout.xml b/core/tests/coretests/res/layout/datepicker_layout.xml
new file mode 100644
index 0000000..a79f87d
--- /dev/null
+++ b/core/tests/coretests/res/layout/datepicker_layout.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 The Android Open Source Project
+
+     Licensed under the Apache License, Version 2.0 (the "License");
+     you may not use this file except in compliance with the License.
+     You may obtain a copy of the License at
+
+          http://www.apache.org/licenses/LICENSE-2.0
+
+     Unless required by applicable law or agreed to in writing, software
+     distributed under the License is distributed on an "AS IS" BASIS,
+     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+     See the License for the specific language governing permissions and
+     limitations under the License.
+-->
+
+<RelativeLayout
+        xmlns:android="http://schemas.android.com/apk/res/android"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent">
+    <DatePicker
+            android:id="@+id/datePicker"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_centerInParent="true"/>
+    <EditText
+            android:id="@+id/belowPicker"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:text="Some Text"
+            android:textAlignment="center"
+            android:layout_below="@id/datePicker"/>
+</RelativeLayout>
diff --git a/core/tests/coretests/res/values-fa/strings.xml b/core/tests/coretests/res/values-fa/strings.xml
new file mode 100644
index 0000000..c83f5f1
--- /dev/null
+++ b/core/tests/coretests/res/values-fa/strings.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="dummy_string">رشتهٔ الکی</string>
+</resources>
diff --git a/core/tests/coretests/res/values/strings.xml b/core/tests/coretests/res/values/strings.xml
index 04b0478..ef915bb 100644
--- a/core/tests/coretests/res/values/strings.xml
+++ b/core/tests/coretests/res/values/strings.xml
@@ -139,4 +139,7 @@
     <!-- RestrictionsManagerTest -->
     <string name="restrictionManager_title">Title</string>
     <string name="restrictionManager_desc">Description</string>
+
+    <!-- ResourcesLocaleResolutionTest -->
+    <string name="dummy_string">dummy string</string>
 </resources>
diff --git a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java b/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
deleted file mode 100644
index 37495e1..0000000
--- a/core/tests/coretests/src/android/content/pm/ManifestDigestTest.java
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.content.pm;
-
-import android.os.Parcel;
-import android.test.AndroidTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.security.MessageDigest;
-
-public class ManifestDigestTest extends AndroidTestCase {
-    private static final byte[] MESSAGE_1 = {
-            (byte) 0x00, (byte) 0xAA, (byte) 0x55, (byte) 0xFF
-    };
-
-    public void testManifestDigest_FromInputStream_Null() {
-        assertNull("Attributes were null, so ManifestDigest.fromAttributes should return null",
-                ManifestDigest.fromInputStream(null));
-    }
-
-    public void testManifestDigest_FromInputStream_ThrowsIoException() {
-        InputStream is = new InputStream() {
-            @Override
-            public int read() throws IOException {
-                throw new IOException();
-            }
-        };
-
-        assertNull("InputStream threw exception, so ManifestDigest should be null",
-                ManifestDigest.fromInputStream(is));
-    }
-
-    public void testManifestDigest_Equals() throws Exception {
-        InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
-        ManifestDigest expected =
-                new ManifestDigest(MessageDigest.getInstance("SHA-256").digest(MESSAGE_1));
-
-        ManifestDigest actual = ManifestDigest.fromInputStream(is);
-        assertEquals(expected, actual);
-
-        ManifestDigest unexpected = new ManifestDigest(new byte[0]);
-        assertFalse(unexpected.equals(actual));
-    }
-
-    public void testManifestDigest_Parcel() throws Exception {
-        InputStream is = new ByteArrayInputStream(MESSAGE_1);
-
-        ManifestDigest digest = ManifestDigest.fromInputStream(is);
-
-        Parcel p = Parcel.obtain();
-        digest.writeToParcel(p, 0);
-        p.setDataPosition(0);
-
-        ManifestDigest fromParcel = ManifestDigest.CREATOR.createFromParcel(p);
-
-        assertEquals("ManifestDigest going through parceling should be the same as before: "
-                + digest.toString() + " and " + fromParcel.toString(), digest,
-                fromParcel);
-    }
-}
diff --git a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
index 9b216cb..d963812 100644
--- a/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
+++ b/core/tests/coretests/src/android/content/pm/VerificationParamsTest.java
@@ -16,7 +16,6 @@
 
 package android.content.pm;
 
-import android.content.pm.ManifestDigest;
 import android.content.pm.VerificationParams;
 import android.net.Uri;
 import android.os.Parcel;
@@ -33,7 +32,6 @@
     private final static String VERIFICATION_URI_STRING = "http://verification.uri/path";
     private final static String ORIGINATING_URI_STRING = "http://originating.uri/path";
     private final static String REFERRER_STRING = "http://referrer.uri/path";
-    private final static byte[] DIGEST_BYTES = "fake digest".getBytes();
     private final static int INSTALLER_UID = 42;
 
     private final static Uri VERIFICATION_URI = Uri.parse(VERIFICATION_URI_STRING);
@@ -42,11 +40,9 @@
 
     private final static int ORIGINATING_UID = 10042;
 
-    private final static ManifestDigest MANIFEST_DIGEST = new ManifestDigest(DIGEST_BYTES);
-
     public void testParcel() throws Exception {
         VerificationParams expected = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         Parcel parcel = Parcel.obtain();
         expected.writeToParcel(parcel, 0);
@@ -61,85 +57,70 @@
         assertEquals(REFERRER, actual.getReferrer());
 
         assertEquals(ORIGINATING_UID, actual.getOriginatingUid());
-
-        assertEquals(MANIFEST_DIGEST, actual.getManifestDigest());
     }
 
     public void testEquals_Success() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertEquals(params1, params2);
     }
 
     public void testEquals_VerificationUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse("http://a.different.uri/"), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_OriginatingUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_Referrer_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse("http://a.different.uri/"), ORIGINATING_UID,
-                new ManifestDigest(DIGEST_BYTES));
+                Uri.parse("http://a.different.uri/"), ORIGINATING_UID);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_Originating_Uid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
-        assertFalse(params1.equals(params2));
-    }
-
-    public void testEquals_ManifestDigest_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID,
-                new ManifestDigest("a different digest".getBytes()));
+                Uri.parse(REFERRER_STRING), 12345);
 
         assertFalse(params1.equals(params2));
     }
 
     public void testEquals_InstallerUid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
         params2.setInstallerUid(INSTALLER_UID);
 
         assertFalse(params1.equals(params2));
@@ -147,78 +128,65 @@
 
     public void testHashCode_Success() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertEquals(params1.hashCode(), params2.hashCode());
     }
 
     public void testHashCode_VerificationUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(null, Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_OriginatingUri_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse("http://a.different.uri/"),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_Referrer_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING), null,
-                ORIGINATING_UID, new ManifestDigest(DIGEST_BYTES));
+                ORIGINATING_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_Originating_Uid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), 12345, new ManifestDigest(DIGEST_BYTES));
-
-        assertFalse(params1.hashCode() == params2.hashCode());
-    }
-
-    public void testHashCode_ManifestDigest_Failure() throws Exception {
-        VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
-
-        VerificationParams params2 = new VerificationParams(
-                Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID,
-                new ManifestDigest("a different digest".getBytes()));
+                Uri.parse(REFERRER_STRING), 12345);
 
         assertFalse(params1.hashCode() == params2.hashCode());
     }
 
     public void testHashCode_InstallerUid_Failure() throws Exception {
         VerificationParams params1 = new VerificationParams(VERIFICATION_URI, ORIGINATING_URI,
-                REFERRER, ORIGINATING_UID, MANIFEST_DIGEST);
+                REFERRER, ORIGINATING_UID);
 
         VerificationParams params2 = new VerificationParams(
                 Uri.parse(VERIFICATION_URI_STRING), Uri.parse(ORIGINATING_URI_STRING),
-                Uri.parse(REFERRER_STRING), ORIGINATING_UID,
-                new ManifestDigest("a different digest".getBytes()));
+                Uri.parse(REFERRER_STRING), ORIGINATING_UID);
         params2.setInstallerUid(INSTALLER_UID);
 
         assertFalse(params1.hashCode() == params2.hashCode());
diff --git a/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
new file mode 100644
index 0000000..55c0031
--- /dev/null
+++ b/core/tests/coretests/src/android/content/res/ResourcesLocaleResolutionTest.java
@@ -0,0 +1,53 @@
+/*
+* Copyright (C) 2015 The Android Open Source Project
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+*      http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+
+package android.content.res;
+
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.DisplayMetrics;
+import android.util.LocaleList;
+
+import java.util.Arrays;
+import java.util.Locale;
+
+public class ResourcesLocaleResolutionTest extends AndroidTestCase {
+    @SmallTest
+    public void testGetResolvedLocale_englishIsAlwaysConsideredSupported() {
+        // First make sure English has no explicit assets other than the default assets
+        final AssetManager assets = getContext().getAssets();
+        final String supportedLocales[] = assets.getNonSystemLocales();
+        for (String languageTag : supportedLocales) {
+            if ("en-XA".equals(languageTag)) {
+                continue;
+            }
+            assertFalse(
+                    "supported locales: " + Arrays.toString(supportedLocales),
+                    "en".equals(Locale.forLanguageTag(languageTag).getLanguage()));
+        }
+
+        final DisplayMetrics dm = new DisplayMetrics();
+        dm.setToDefaults();
+        final Configuration cfg = new Configuration();
+        cfg.setToDefaults();
+        // Avestan and English have no assets, but Persian does.
+        cfg.setLocales(LocaleList.forLanguageTags("ae,en,fa"));
+        Resources res = new Resources(assets, dm, cfg);
+        // We should get English, because it is always considered supported.
+        assertEquals("en", res.getResolvedLocale().toLanguageTag());
+    }
+}
+
diff --git a/core/tests/coretests/src/android/widget/DatePickerActivity.java b/core/tests/coretests/src/android/widget/DatePickerActivity.java
new file mode 100644
index 0000000..c3b25a1
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerActivity.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.app.Activity;
+import android.os.Bundle;
+import com.android.frameworks.coretests.R;
+
+/**
+ * A minimal application for DatePickerFocusTest.
+ */
+public class DatePickerActivity extends Activity {
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.datepicker_layout);
+    }
+}
diff --git a/core/tests/coretests/src/android/widget/DatePickerFocusTest.java b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
new file mode 100644
index 0000000..513e40f
--- /dev/null
+++ b/core/tests/coretests/src/android/widget/DatePickerFocusTest.java
@@ -0,0 +1,250 @@
+/*
+ * Copyright (C) 2008 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.widget;
+
+import android.app.Activity;
+import android.app.Instrumentation;
+import android.os.SystemClock;
+import android.test.ActivityInstrumentationTestCase2;
+import android.view.KeyEvent;
+import android.view.View;
+
+import com.android.frameworks.coretests.R;
+
+/**
+ * Test {@link DatePicker} focus changes.
+ */
+public class DatePickerFocusTest extends ActivityInstrumentationTestCase2<DatePickerActivity> {
+
+    private Activity mActivity;
+    private Instrumentation mInstrumentation;
+    private DatePicker mDatePicker;
+
+    public DatePickerFocusTest() {
+        super(DatePickerActivity.class);
+    }
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+
+        mActivity = getActivity();
+        mInstrumentation = getInstrumentation();
+
+        mDatePicker = (DatePicker) mActivity.findViewById(R.id.datePicker);
+    }
+
+    /**
+     * Tabs (forward and backward) through the DatePicker to ensure the correct
+     * Views gain focus.
+     */
+    public void testFocusTravel() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertTrue(mDatePicker.requestFocus());
+            }
+        });
+        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.next);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(R.id.belowPicker);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.next);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        sendShiftKey(KeyEvent.KEYCODE_TAB);
+        assertViewHasFocus(com.android.internal.R.id.date_picker_header_year);
+    }
+
+    private void sendKey(int keycode) {
+        mInstrumentation.sendKeyDownUpSync(keycode);
+        mInstrumentation.waitForIdleSync();
+    }
+
+    private void assertViewHasFocus(final int id) throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View view = mActivity.findViewById(id);
+                assertTrue(view.hasFocus());
+            }
+        });
+    }
+
+    private void sendShiftKey(int keycode) {
+        final KeyEvent shiftDown = new KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_SHIFT_LEFT);
+        mInstrumentation.sendKeySync(shiftDown);
+
+        final KeyEvent keyDown = new KeyEvent(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), KeyEvent.ACTION_DOWN, keycode, 0,
+                KeyEvent.META_SHIFT_ON);
+        mInstrumentation.sendKeySync(keyDown);
+
+        final KeyEvent keyUp = new KeyEvent(SystemClock.uptimeMillis(),
+                SystemClock.uptimeMillis(), KeyEvent.ACTION_UP, keycode, 0,
+                KeyEvent.META_SHIFT_ON);
+        mInstrumentation.sendKeySync(keyUp);
+
+        final KeyEvent shiftUp = new KeyEvent(KeyEvent.ACTION_UP, KeyEvent.KEYCODE_SHIFT_LEFT);
+        mInstrumentation.sendKeySync(shiftUp);
+
+        mInstrumentation.waitForIdleSync();
+    }
+
+    /**
+     * Tests to ensure the keyboard can select the current year.
+     */
+    public void testYearChoice() throws Throwable {
+        setKnownDate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View year = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_header_year);
+                assertTrue(year.requestFocus());
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View yearSelect = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_year_picker);
+                assertEquals(yearSelect, mDatePicker.findFocus());
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View yearSelect = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_year_picker);
+                assertNotSame(View.VISIBLE, yearSelect.getVisibility());
+                View year = mDatePicker.
+                        findViewById(com.android.internal.R.id.date_picker_header_year);
+                assertTrue(year.hasFocus());
+                assertEquals(2014, mDatePicker.getYear());
+            }
+        });
+    }
+
+    public void testArrowThroughDays() throws Throwable {
+        setKnownDate();
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                View prev = mDatePicker.findViewById(com.android.internal.R.id.next);
+                prev.requestFocus();
+            }
+        });
+        sendKey(KeyEvent.KEYCODE_TAB);
+        // Should select the current date and the date shouldn't change
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 31, 2015);
+        // Move right to January 24, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 24, 2016);
+        // Move down to January 31, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 31, 2016);
+        // Move up to January 5, 2016
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 5, 2016);
+        // Move up to prev arrow key
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        assertViewHasFocus(com.android.internal.R.id.prev);
+        // tab back into the day-selection pager
+        sendKey(KeyEvent.KEYCODE_TAB);
+        sendKey(KeyEvent.KEYCODE_TAB);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        assertDateIs(1, 5, 2016);
+
+        // Move up out again, then down back into the day-selection pager.
+        // It should land right below the prev button (1/3/2016)
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertViewHasFocus(com.android.internal.R.id.day_picker_view_pager);
+        assertDateIs(1, 3, 2016);
+
+        // Move left to previous month (12/12/2015)
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 12, 2015);
+        // Now make sure the start of the month works
+        // Move up to 12/5/2015 and right to 1/1/2016
+        sendKey(KeyEvent.KEYCODE_DPAD_UP);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(1, 1, 2016);
+        // Now make sure the left key goes back to previous month (12/5/2015)
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 5, 2015);
+        // Now go to a mismatched row (no such row on previous month)
+        // This moves over to 1/31/2016 and then left to 12/31/2015
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_RIGHT);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_DOWN);
+        sendKey(KeyEvent.KEYCODE_DPAD_LEFT);
+        sendKey(KeyEvent.KEYCODE_ENTER);
+        assertDateIs(12, 31, 2015);
+    }
+
+    private void assertDateIs(int month, final int day, final int year) throws Throwable {
+        final int monthInt = month - 1; // months are 0-based
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                assertEquals(day, mDatePicker.getDayOfMonth());
+                assertEquals(year, mDatePicker.getYear());
+                assertEquals(monthInt, mDatePicker.getMonth());
+            }
+        });
+    }
+
+    private void setKnownDate() throws Throwable {
+        runTestOnUiThread(new Runnable() {
+            @Override
+            public void run() {
+                mDatePicker.updateDate(2015, 11, 31); // December 31, 2015
+            }
+        });
+        mInstrumentation.waitForIdleSync();
+    }
+}
diff --git a/data/fonts/fonts.xml b/data/fonts/fonts.xml
index 554b6f1..731bf42 100644
--- a/data/fonts/fonts.xml
+++ b/data/fonts/fonts.xml
@@ -344,7 +344,7 @@
     <family>
         <font weight="400" style="normal">NanumGothic.ttf</font>
     </family>
-    <family lang="und-Qaae">
+    <family lang="und-Zsye">
         <font weight="400" style="normal">NotoColorEmoji.ttf</font>
     </family>
     <family>
diff --git a/drm/java/android/drm/DrmManagerClient.java b/drm/java/android/drm/DrmManagerClient.java
index c05ea2e..704f0ce 100644
--- a/drm/java/android/drm/DrmManagerClient.java
+++ b/drm/java/android/drm/DrmManagerClient.java
@@ -38,13 +38,14 @@
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * The main programming interface for the DRM framework. An application must instantiate this class
  * to access DRM agents through the DRM framework.
  *
  */
-public class DrmManagerClient {
+public class DrmManagerClient implements AutoCloseable {
     /**
      * Indicates that a request was successful or that no error occurred.
      */
@@ -61,6 +62,7 @@
     HandlerThread mEventThread;
     private static final String TAG = "DrmManagerClient";
 
+    private final AtomicBoolean mClosed = new AtomicBoolean();
     private final CloseGuard mCloseGuard = CloseGuard.get();
 
     static {
@@ -117,7 +119,6 @@
 
     private int mUniqueId;
     private long mNativeContext;
-    private volatile boolean mReleased;
     private Context mContext;
     private InfoHandler mInfoHandler;
     private EventHandler mEventHandler;
@@ -261,41 +262,47 @@
     @Override
     protected void finalize() throws Throwable {
         try {
-            if (mCloseGuard != null) {
-                mCloseGuard.warnIfOpen();
-            }
-            release();
+            mCloseGuard.warnIfOpen();
+            close();
         } finally {
             super.finalize();
         }
     }
 
     /**
-     * Releases resources associated with the current session of DrmManagerClient.
-     *
-     * It is considered good practice to call this method when the {@link DrmManagerClient} object
-     * is no longer needed in your application. After release() is called,
-     * {@link DrmManagerClient} is no longer usable since it has lost all of its required resource.
+     * Releases resources associated with the current session of
+     * DrmManagerClient. It is considered good practice to call this method when
+     * the {@link DrmManagerClient} object is no longer needed in your
+     * application. After this method is called, {@link DrmManagerClient} is no
+     * longer usable since it has lost all of its required resource.
      */
-    public void release() {
-        if (mReleased) return;
-        mReleased = true;
-
-        if (mEventHandler != null) {
-            mEventThread.quit();
-            mEventThread = null;
-        }
-        if (mInfoHandler != null) {
-            mInfoThread.quit();
-            mInfoThread = null;
-        }
-        mEventHandler = null;
-        mInfoHandler = null;
-        mOnEventListener = null;
-        mOnInfoListener = null;
-        mOnErrorListener = null;
-        _release(mUniqueId);
+    @Override
+    public void close() {
         mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            if (mEventHandler != null) {
+                mEventThread.quit();
+                mEventThread = null;
+            }
+            if (mInfoHandler != null) {
+                mInfoThread.quit();
+                mInfoThread = null;
+            }
+            mEventHandler = null;
+            mInfoHandler = null;
+            mOnEventListener = null;
+            mOnInfoListener = null;
+            mOnErrorListener = null;
+            _release(mUniqueId);
+        }
+    }
+
+    /**
+     * @deprecated replaced by {@link #close()}.
+     */
+    @Deprecated
+    public void release() {
+        close();
     }
 
     /**
diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java
index da58884..175c726 100644
--- a/graphics/java/android/graphics/BitmapFactory.java
+++ b/graphics/java/android/graphics/BitmapFactory.java
@@ -163,8 +163,11 @@
         public boolean inPremultiplied;
 
         /**
-         * If dither is true, the decoder will attempt to dither the decoded
-         * image.
+         * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+         * ignored.
+         *
+         * In {@link android.os.Build.VERSION_CODES#M} and below, if dither is
+         * true, the decoder will attempt to dither the decoded image.
          */
         public boolean inDither;
 
@@ -308,7 +311,11 @@
         public boolean inInputShareable;
 
         /**
-         * If inPreferQualityOverSpeed is set to true, the decoder will try to
+         * @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this is
+         * ignored.  The output will always be high quality.
+         *
+         * In {@link android.os.Build.VERSION_CODES#M} and below, if
+         * inPreferQualityOverSpeed is set to true, the decoder will try to
          * decode the reconstructed image to a higher quality even at the
          * expense of the decoding speed. Currently the field only affects JPEG
          * decode, in the case of which a more accurate, but slightly slower,
@@ -347,8 +354,6 @@
          */
         public byte[] inTempStorage;
 
-        private native void requestCancel();
-
         /**
          * Flag to indicate that cancel has been called on this object.  This
          * is useful if there's an intermediary that wants to first decode the
@@ -359,16 +364,19 @@
         public boolean mCancel;
 
         /**
-         *  This can be called from another thread while this options object is
-         *  inside a decode... call. Calling this will notify the decoder that
-         *  it should cancel its operation. This is not guaranteed to cancel
-         *  the decode, but if it does, the decoder... operation will return
-         *  null, or if inJustDecodeBounds is true, will set outWidth/outHeight
+         *  @deprecated As of {@link android.os.Build.VERSION_CODES#N}, this
+         *  will not affect the decode, though it will still set mCancel.
+         *
+         *  In {@link android.os.Build.VERSION_CODES#M} and below, if this can
+         *  be called from another thread while this options object is inside
+         *  a decode... call. Calling this will notify the decoder that it
+         *  should cancel its operation. This is not guaranteed to cancel the
+         *  decode, but if it does, the decoder... operation will return null,
+         *  or if inJustDecodeBounds is true, will set outWidth/outHeight
          *  to -1
          */
         public void requestCancelDecode() {
             mCancel = true;
-            requestCancel();
         }
     }
 
diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java
index d5166ab..1cc5346 100644
--- a/graphics/java/android/graphics/Canvas.java
+++ b/graphics/java/android/graphics/Canvas.java
@@ -654,6 +654,12 @@
     /**
      * Return, in ctm, the current transformation matrix. This does not alter
      * the matrix in the canvas, but just returns a copy of it.
+     *
+     * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+     * matrix when passed to a View or Drawable, as it is implementation defined where in the
+     * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+     * irrespective of the current matrix, or to track relevant transform state outside of the
+     * canvas.
      */
     @Deprecated
     public void getMatrix(@NonNull Matrix ctm) {
@@ -663,6 +669,12 @@
     /**
      * Return a new matrix with a copy of the canvas' current transformation
      * matrix.
+     *
+     * @deprecated {@link #isHardwareAccelerated() Hardware accelerated} canvases may have any
+     * matrix when passed to a View or Drawable, as it is implementation defined where in the
+     * hierarchy such canvases are created. It is recommended in such cases to either draw contents
+     * irrespective of the current matrix, or to track relevant transform state outside of the
+     * canvas.
      */
     @Deprecated
     public final @NonNull Matrix getMatrix() {
@@ -812,6 +824,7 @@
      * @deprecated Unlike all other clip calls this API does not respect the
      *             current matrix. Use {@link #clipRect(Rect)} as an alternative.
      */
+    @Deprecated
     public boolean clipRegion(@NonNull Region region, @NonNull Region.Op op) {
         return native_clipRegion(mNativeCanvasWrapper, region.ni(), op.nativeInt);
     }
@@ -829,6 +842,7 @@
      * @deprecated Unlike all other clip calls this API does not respect the
      *             current matrix. Use {@link #clipRect(Rect)} as an alternative.
      */
+    @Deprecated
     public boolean clipRegion(@NonNull Region region) {
         return clipRegion(region, Region.Op.INTERSECT);
     }
@@ -1830,16 +1844,16 @@
      * Draw the text in the array, with each character's origin specified by
      * the pos array.
      *
-     * This method does not support glyph composition and decomposition and
-     * should therefore not be used to render complex scripts. It also doesn't
-     * handle supplementary characters (eg emoji).
-     *
      * @param text     The text to be drawn
      * @param index    The index of the first character to draw
      * @param count    The number of characters to draw, starting from index.
      * @param pos      Array of [x,y] positions, used to position each
      *                 character
      * @param paint    The paint used for the text (e.g. color, size, style)
+     *
+     * @deprecated This method does not support glyph composition and decomposition and
+     * should therefore not be used to render complex scripts. It also doesn't
+     * handle supplementary characters (eg emoji).
      */
     @Deprecated
     public void drawPosText(@NonNull char[] text, int index, int count,
@@ -1857,13 +1871,13 @@
      * Draw the text in the array, with each character's origin specified by
      * the pos array.
      *
-     * This method does not support glyph composition and decomposition and
-     * should therefore not be used to render complex scripts. It also doesn't
-     * handle supplementary characters (eg emoji).
-     *
      * @param text  The text to be drawn
      * @param pos   Array of [x,y] positions, used to position each character
      * @param paint The paint used for the text (e.g. color, size, style)
+     *
+     * @deprecated This method does not support glyph composition and decomposition and
+     * should therefore not be used to render complex scripts. It also doesn't
+     * handle supplementary characters (eg emoji).
      */
     @Deprecated
     public void drawPosText(@NonNull String text, @NonNull @Size(multiple=2) float[] pos,
diff --git a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
index 1857345..84ca546 100644
--- a/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/AnimatedVectorDrawable.java
@@ -19,6 +19,7 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.Animator.AnimatorListener;
+import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.res.ColorStateList;
@@ -140,6 +141,15 @@
     /** Local, mutable animator set. */
     private final AnimatorSet mAnimatorSet = new AnimatorSet();
 
+
+    private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
+            new ValueAnimator.AnimatorUpdateListener() {
+                @Override
+                public void onAnimationUpdate(ValueAnimator animation) {
+                    invalidateSelf();
+                }
+            };
+
     /**
      * The resources against which this drawable was created. Used to attempt
      * to inflate animators if applyTheme() doesn't get called.
@@ -201,9 +211,6 @@
     @Override
     public void draw(Canvas canvas) {
         mAnimatedVectorState.mVectorDrawable.draw(canvas);
-        if (isStarted()) {
-            invalidateSelf();
-        }
     }
 
     @Override
@@ -486,6 +493,7 @@
          *            animators, or {@code null} if not available
          */
         public void prepareLocalAnimators(@NonNull AnimatorSet animatorSet,
+                @NonNull ValueAnimator.AnimatorUpdateListener updateListener,
                 @Nullable Resources res) {
             // Check for uninflated animators. We can remove this after we add
             // support for Animator.applyTheme(). See comments in inflate().
@@ -511,6 +519,17 @@
                     final Animator nextAnim = prepareLocalAnimator(i);
                     builder.with(nextAnim);
                 }
+
+                // Setup a value animator to get animation update callbacks.
+                long totalDuration = animatorSet.getTotalDuration();
+                ValueAnimator updateAnim = ValueAnimator.ofFloat(0f, 1f);
+                if (totalDuration == ValueAnimator.DURATION_INFINITE) {
+                    updateAnim.setRepeatCount(ValueAnimator.INFINITE);
+                } else {
+                    updateAnim.setDuration(totalDuration);
+                }
+                updateAnim.addUpdateListener(updateListener);
+                builder.with(updateAnim);
             }
         }
 
@@ -603,7 +622,7 @@
     @NonNull
     private void ensureAnimatorSet() {
         if (!mHasAnimatorSet) {
-            mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mRes);
+            mAnimatedVectorState.prepareLocalAnimators(mAnimatorSet, mUpdateListener, mRes);
             mHasAnimatorSet = true;
             mRes = null;
         }
diff --git a/include/androidfw/AssetManager.h b/include/androidfw/AssetManager.h
index 3d4e47d..914ac3d 100644
--- a/include/androidfw/AssetManager.h
+++ b/include/androidfw/AssetManager.h
@@ -100,16 +100,17 @@
      * then on success, *cookie is set to the value corresponding to the
      * newly-added asset source.
      */
-    bool addAssetPath(const String8& path, int32_t* cookie, bool appAsLib=false);
+    bool addAssetPath(const String8& path, int32_t* cookie,
+        bool appAsLib=false, bool isSystemAsset=false);
     bool addOverlayPath(const String8& path, int32_t* cookie);
 
-    /*                                                                       
+    /*
      * Convenience for adding the standard system assets.  Uses the
      * ANDROID_ROOT environment variable to find them.
      */
     bool addDefaultAssets();
 
-    /*                                                                       
+    /*
      * Iterate over the asset paths in this manager.  (Previously
      * added via addAssetPath() and addDefaultAssets().)  On first call,
      * 'cookie' must be 0, resulting in the first cookie being returned.
@@ -118,7 +119,7 @@
      */
     int32_t nextAssetPath(const int32_t cookie) const;
 
-    /*                                                                       
+    /*
      * Return an asset path in the manager.  'which' must be between 0 and
      * countAssetPaths().
      */
@@ -221,11 +222,11 @@
      * the current data.
      */
     bool isUpToDate();
-    
+
     /**
      * Get the known locales for this asset manager object.
      */
-    void getLocales(Vector<String8>* locales) const;
+    void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
 
     /**
      * Generate idmap data to translate resources IDs between a package and a
@@ -237,11 +238,13 @@
 private:
     struct asset_path
     {
-        asset_path() : path(""), type(kFileTypeRegular), idmap(""), isSystemOverlay(false) {}
+        asset_path() : path(""), type(kFileTypeRegular), idmap(""),
+                       isSystemOverlay(false), isSystemAsset(false) {}
         String8 path;
         FileType type;
         String8 idmap;
         bool isSystemOverlay;
+        bool isSystemAsset;
     };
 
     Asset* openInPathLocked(const char* fileName, AccessMode mode,
diff --git a/include/androidfw/ResourceTypes.h b/include/androidfw/ResourceTypes.h
index 49b6333..428a2b8 100644
--- a/include/androidfw/ResourceTypes.h
+++ b/include/androidfw/ResourceTypes.h
@@ -1552,9 +1552,9 @@
 
     status_t add(Asset* asset, const int32_t cookie=-1, bool copyData=false);
     status_t add(Asset* asset, Asset* idmapAsset, const int32_t cookie=-1, bool copyData=false,
-            bool appAsLib=false);
+            bool appAsLib=false, bool isSystemAsset=false);
 
-    status_t add(ResTable* src);
+    status_t add(ResTable* src, bool isSystemAsset=false);
     status_t addEmpty(const int32_t cookie);
 
     status_t getError() const;
@@ -1822,9 +1822,9 @@
 
     // Return the configurations (ResTable_config) that we know about
     void getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap=false,
-            bool ignoreAndroidPackage=false) const;
+            bool ignoreAndroidPackage=false, bool includeSystemConfigs=true) const;
 
-    void getLocales(Vector<String8>* locales) const;
+    void getLocales(Vector<String8>* locales, bool includeSystemLocales=true) const;
 
     // Generate an idmap.
     //
@@ -1860,7 +1860,7 @@
     typedef Vector<Type*> TypeList;
 
     status_t addInternal(const void* data, size_t size, const void* idmapData, size_t idmapDataSize,
-            bool appAsLib, const int32_t cookie, bool copyData);
+            bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset=false);
 
     ssize_t getResourcePackageIndex(uint32_t resID) const;
 
@@ -1873,10 +1873,11 @@
             size_t nameLen, uint32_t* outTypeSpecFlags) const;
 
     status_t parsePackage(
-        const ResTable_package* const pkg, const Header* const header, bool appAsLib);
+        const ResTable_package* const pkg, const Header* const header,
+        bool appAsLib, bool isSystemAsset);
 
     void print_value(const Package* pkg, const Res_value& value) const;
-    
+
     mutable Mutex               mLock;
 
     status_t                    mError;
diff --git a/libs/androidfw/AssetManager.cpp b/libs/androidfw/AssetManager.cpp
index 8a03b94..6913f43 100644
--- a/libs/androidfw/AssetManager.cpp
+++ b/libs/androidfw/AssetManager.cpp
@@ -176,7 +176,8 @@
     delete[] mVendor;
 }
 
-bool AssetManager::addAssetPath(const String8& path, int32_t* cookie, bool appAsLib)
+bool AssetManager::addAssetPath(
+        const String8& path, int32_t* cookie, bool appAsLib, bool isSystemAsset)
 {
     AutoMutex _l(mLock);
 
@@ -222,6 +223,7 @@
     }
     delete manifestAsset;
 
+    ap.isSystemAsset = isSystemAsset;
     mAssetPaths.add(ap);
 
     // new paths are always added at the end
@@ -233,6 +235,7 @@
     // Load overlays, if any
     asset_path oap;
     for (size_t idx = 0; mZipSet.getOverlay(ap.path, idx, &oap); idx++) {
+        oap.isSystemAsset = isSystemAsset;
         mAssetPaths.add(oap);
     }
 #endif
@@ -340,7 +343,7 @@
     String8 path(root);
     path.appendPath(kSystemAssets);
 
-    return addAssetPath(path, NULL);
+    return addAssetPath(path, NULL, false /* appAsLib */, true /* isSystemAsset */);
 }
 
 int32_t AssetManager::nextAssetPath(const int32_t cookie) const
@@ -682,10 +685,10 @@
         ALOGV("Installing resource asset %p in to table %p\n", ass, mResources);
         if (sharedRes != NULL) {
             ALOGV("Copying existing resources for %s", ap.path.string());
-            mResources->add(sharedRes);
+            mResources->add(sharedRes, ap.isSystemAsset);
         } else {
             ALOGV("Parsing resources for %s", ap.path.string());
-            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib);
+            mResources->add(ass, idmap, nextEntryIdx + 1, !shared, appAsLib, ap.isSystemAsset);
         }
         onlyEmptyResources = false;
 
@@ -831,11 +834,11 @@
     return mZipSet.isUpToDate();
 }
 
-void AssetManager::getLocales(Vector<String8>* locales) const
+void AssetManager::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     ResTable* res = mResources;
     if (res != NULL) {
-        res->getLocales(locales);
+        res->getLocales(locales, includeSystemLocales);
     }
 
     const size_t numLocales = locales->size();
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 21b543e..44f92c7 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -3080,13 +3080,16 @@
 // table that defined the package); the ones after are skins on top of it.
 struct ResTable::PackageGroup
 {
-    PackageGroup(ResTable* _owner, const String16& _name, uint32_t _id, bool appAsLib)
+    PackageGroup(
+            ResTable* _owner, const String16& _name, uint32_t _id,
+            bool appAsLib, bool _isSystemAsset)
         : owner(_owner)
         , name(_name)
         , id(_id)
         , largestTypeId(0)
         , bags(NULL)
         , dynamicRefTable(static_cast<uint8_t>(_id), appAsLib)
+        , isSystemAsset(_isSystemAsset)
     { }
 
     ~PackageGroup() {
@@ -3178,6 +3181,10 @@
     // by having these tables in a per-package scope rather than
     // per-package-group.
     DynamicRefTable                 dynamicRefTable;
+
+    // If the package group comes from a system asset. Used in
+    // determining non-system locales.
+    const bool                      isSystemAsset;
 };
 
 struct ResTable::bag_set
@@ -3572,8 +3579,9 @@
             copyData);
 }
 
-status_t ResTable::add(Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
-        bool appAsLib) {
+status_t ResTable::add(
+        Asset* asset, Asset* idmapAsset, const int32_t cookie, bool copyData,
+        bool appAsLib, bool isSystemAsset) {
     const void* data = asset->getBuffer(true);
     if (data == NULL) {
         ALOGW("Unable to get buffer of resource asset file");
@@ -3592,20 +3600,21 @@
     }
 
     return addInternal(data, static_cast<size_t>(asset->getLength()),
-            idmapData, idmapSize, appAsLib, cookie, copyData);
+            idmapData, idmapSize, appAsLib, cookie, copyData, isSystemAsset);
 }
 
-status_t ResTable::add(ResTable* src)
+status_t ResTable::add(ResTable* src, bool isSystemAsset)
 {
     mError = src->mError;
 
-    for (size_t i=0; i<src->mHeaders.size(); i++) {
+    for (size_t i=0; i < src->mHeaders.size(); i++) {
         mHeaders.add(src->mHeaders[i]);
     }
 
-    for (size_t i=0; i<src->mPackageGroups.size(); i++) {
+    for (size_t i=0; i < src->mPackageGroups.size(); i++) {
         PackageGroup* srcPg = src->mPackageGroups[i];
-        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id, false);
+        PackageGroup* pg = new PackageGroup(this, srcPg->name, srcPg->id,
+                false /* appAsLib */, isSystemAsset || srcPg->isSystemAsset);
         for (size_t j=0; j<srcPg->packages.size(); j++) {
             pg->packages.add(srcPg->packages[j]);
         }
@@ -3646,7 +3655,7 @@
 }
 
 status_t ResTable::addInternal(const void* data, size_t dataSize, const void* idmapData, size_t idmapDataSize,
-        bool appAsLib, const int32_t cookie, bool copyData)
+        bool appAsLib, const int32_t cookie, bool copyData, bool isSystemAsset)
 {
     if (!data) {
         return NO_ERROR;
@@ -3749,7 +3758,8 @@
                 return (mError=BAD_TYPE);
             }
 
-            if (parsePackage((ResTable_package*)chunk, header, appAsLib) != NO_ERROR) {
+            if (parsePackage(
+                    (ResTable_package*)chunk, header, appAsLib, isSystemAsset) != NO_ERROR) {
                 return mError;
             }
             curPackage++;
@@ -5663,7 +5673,7 @@
 }
 
 void ResTable::getConfigurations(Vector<ResTable_config>* configs, bool ignoreMipmap,
-        bool ignoreAndroidPackage) const {
+        bool ignoreAndroidPackage, bool includeSystemConfigs) const {
     const size_t packageCount = mPackageGroups.size();
     String16 android("android");
     for (size_t i = 0; i < packageCount; i++) {
@@ -5671,6 +5681,9 @@
         if (ignoreAndroidPackage && android == packageGroup->name) {
             continue;
         }
+        if (!includeSystemConfigs && packageGroup->isSystemAsset) {
+            continue;
+        }
         const size_t typeCount = packageGroup->types.size();
         for (size_t j = 0; j < typeCount; j++) {
             const TypeList& typeList = packageGroup->types[j];
@@ -5707,11 +5720,14 @@
     }
 }
 
-void ResTable::getLocales(Vector<String8>* locales) const
+void ResTable::getLocales(Vector<String8>* locales, bool includeSystemLocales) const
 {
     Vector<ResTable_config> configs;
     ALOGV("calling getConfigurations");
-    getConfigurations(&configs);
+    getConfigurations(&configs,
+            false /* ignoreMipmap */,
+            false /* ignoreAndroidPackage */,
+            includeSystemLocales /* includeSystemConfigs */);
     ALOGV("called getConfigurations size=%d", (int)configs.size());
     const size_t I = configs.size();
 
@@ -5937,7 +5953,7 @@
 }
 
 status_t ResTable::parsePackage(const ResTable_package* const pkg,
-                                const Header* const header, bool appAsLib)
+                                const Header* const header, bool appAsLib, bool isSystemAsset)
 {
     const uint8_t* base = (const uint8_t*)pkg;
     status_t err = validate_chunk(&pkg->header, sizeof(*pkg) - sizeof(pkg->typeIdOffset),
@@ -5985,8 +6001,8 @@
     if (id >= 256) {
         LOG_ALWAYS_FATAL("Package id out of range");
         return NO_ERROR;
-    } else if (id == 0 || appAsLib) {
-        // This is a library so assign an ID
+    } else if (id == 0 || appAsLib || isSystemAsset) {
+        // This is a library or a system asset, so assign an ID
         id = mNextPackageId++;
     }
 
@@ -6018,7 +6034,7 @@
 
         char16_t tmpName[sizeof(pkg->name)/sizeof(pkg->name[0])];
         strcpy16_dtoh(tmpName, pkg->name, sizeof(pkg->name)/sizeof(pkg->name[0]));
-        group = new PackageGroup(this, String16(tmpName), id, appAsLib);
+        group = new PackageGroup(this, String16(tmpName), id, appAsLib, isSystemAsset);
         if (group == NULL) {
             delete package;
             return (mError=NO_MEMORY);
diff --git a/libs/hwui/Android.mk b/libs/hwui/Android.mk
index f48c509..11056d4 100644
--- a/libs/hwui/Android.mk
+++ b/libs/hwui/Android.mk
@@ -108,6 +108,7 @@
     hwui_src_files += \
         BakedOpDispatcher.cpp \
         BakedOpRenderer.cpp \
+        BakedOpState.cpp \
         OpReorderer.cpp \
         RecordingCanvas.cpp
 
diff --git a/libs/hwui/BakedOpDispatcher.cpp b/libs/hwui/BakedOpDispatcher.cpp
index 0f0768f..332a204 100644
--- a/libs/hwui/BakedOpDispatcher.cpp
+++ b/libs/hwui/BakedOpDispatcher.cpp
@@ -79,7 +79,9 @@
             .setTransform(Matrix4::identity(), TransformFlags::None)
             .setModelViewIdentityEmptyBounds()
             .build();
-    renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+    ClipRect renderTargetClip(opList.clip);
+    const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+    renderer.renderGlop(nullptr, clip, glop);
 }
 
 void BakedOpDispatcher::onMergedPatchOps(BakedOpRenderer& renderer,
@@ -183,7 +185,9 @@
             .setTransform(Matrix4::identity(), TransformFlags::None)
             .setModelViewIdentityEmptyBounds()
             .build();
-    renderer.renderGlop(nullptr, opList.clipSideFlags ? &opList.clip : nullptr, glop);
+    ClipRect renderTargetClip(opList.clip);
+    const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
+    renderer.renderGlop(nullptr, clip, glop);
 }
 
 static void renderTextShadow(BakedOpRenderer& renderer, FontRenderer& fontRenderer,
@@ -224,7 +228,7 @@
 };
 
 static void renderTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state,
-        const Rect* renderClip, TextRenderType renderType) {
+        const ClipBase* renderClip, TextRenderType renderType) {
     FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
 
     if (CC_UNLIKELY(PaintUtils::hasTextShadow(op.paint))) {
@@ -272,7 +276,7 @@
 
     bool forceFinish = (renderType == TextRenderType::Flush);
     bool mustDirtyRenderTarget = renderer.offscreenRenderTarget();
-    const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect : nullptr;
+    const Rect* localOpClip = pureTranslate ? &state.computedState.clipRect() : nullptr;
     fontRenderer.renderPosText(op.paint, localOpClip,
             (const char*) op.glyphs, op.glyphCount, x, y,
             op.positions, mustDirtyRenderTarget ? &layerBounds : nullptr, &functor, forceFinish);
@@ -287,7 +291,8 @@
 
 void BakedOpDispatcher::onMergedTextOps(BakedOpRenderer& renderer,
         const MergedBakedOpList& opList) {
-    const Rect* clip = opList.clipSideFlags ? &opList.clip : nullptr;
+    ClipRect renderTargetClip(opList.clip);
+    const ClipBase* clip = opList.clipSideFlags ? &renderTargetClip : nullptr;
     for (size_t i = 0; i < opList.count; i++) {
         const BakedOpState& state = *(opList.states[i]);
         const TextOp& op = *(static_cast<const TextOp*>(state.op));
@@ -701,14 +706,13 @@
 }
 
 void BakedOpDispatcher::onTextOp(BakedOpRenderer& renderer, const TextOp& op, const BakedOpState& state) {
-    const Rect* clip = state.computedState.clipSideFlags ? &state.computedState.clipRect : nullptr;
-    renderTextOp(renderer, op, state, clip, TextRenderType::Flush);
+    renderTextOp(renderer, op, state, state.computedState.getClipIfNeeded(), TextRenderType::Flush);
 }
 
 void BakedOpDispatcher::onTextOnPathOp(BakedOpRenderer& renderer, const TextOnPathOp& op, const BakedOpState& state) {
     // Note: can't trust clipSideFlags since we record with unmappedBounds == clip.
     // TODO: respect clipSideFlags, once we record with bounds
-    const Rect* renderTargetClip = &state.computedState.clipRect;
+    auto renderTargetClip = state.computedState.clipState;
 
     FontRenderer& fontRenderer = renderer.caches().fontRenderer.getFontRenderer();
     fontRenderer.setFont(op.paint, SkMatrix::I());
diff --git a/libs/hwui/BakedOpRenderer.cpp b/libs/hwui/BakedOpRenderer.cpp
index f8282dc..a0d5fae 100644
--- a/libs/hwui/BakedOpRenderer.cpp
+++ b/libs/hwui/BakedOpRenderer.cpp
@@ -60,27 +60,67 @@
 }
 
 void BakedOpRenderer::endLayer() {
+    if (mRenderTarget.stencil) {
+        // if stencil was used for clipping, detach it and return it to pool
+        glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT, GL_RENDERBUFFER, 0);
+        LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "glfbrb endlayer failed");
+        mCaches.renderBufferCache.put(mRenderTarget.stencil);
+        mRenderTarget.stencil = nullptr;
+    }
+    mRenderTarget.lastStencilClip = nullptr;
+
     mRenderTarget.offscreenBuffer->updateMeshFromRegion();
-    mRenderTarget.offscreenBuffer = nullptr;
+    mRenderTarget.offscreenBuffer = nullptr; // It's in drawLayerOp's hands now.
 
     // Detach the texture from the FBO
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, 0, 0);
     LOG_ALWAYS_FATAL_IF(GLUtils::dumpGLErrors(), "endLayer FAILED");
     mRenderState.deleteFramebuffer(mRenderTarget.frameBufferId);
-    mRenderTarget.frameBufferId = -1;
+    mRenderTarget.frameBufferId = 0;
 }
 
 void BakedOpRenderer::startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {
+    LOG_ALWAYS_FATAL_IF(mRenderTarget.frameBufferId != 0, "primary framebufferId must be 0");
     mRenderState.bindFramebuffer(0);
     setViewport(width, height);
-    mCaches.clearGarbage();
 
     if (!mOpaque) {
         clearColorBuffer(repaintRect);
     }
+
+    mRenderState.debugOverdraw(true, true);
 }
 
-void BakedOpRenderer::endFrame() {
+void BakedOpRenderer::endFrame(const Rect& repaintRect) {
+    if (CC_UNLIKELY(Properties::debugOverdraw)) {
+        ClipRect overdrawClip(repaintRect);
+        Rect viewportRect(mRenderTarget.viewportWidth, mRenderTarget.viewportHeight);
+        // overdraw visualization
+        for (int i = 1; i <= 4; i++) {
+            if (i < 4) {
+                // nth level of overdraw tests for n+1 draws per pixel
+                mRenderState.stencil().enableDebugTest(i + 1, false);
+            } else {
+                // 4th level tests for 4 or higher draws per pixel
+                mRenderState.stencil().enableDebugTest(4, true);
+            }
+
+            SkPaint paint;
+            paint.setColor(mCaches.getOverdrawColor(i));
+            Glop glop;
+            GlopBuilder(mRenderState, mCaches, &glop)
+                    .setRoundRectClipState(nullptr)
+                    .setMeshUnitQuad()
+                    .setFillPaint(paint, 1.0f)
+                    .setTransform(Matrix4::identity(), TransformFlags::None)
+                    .setModelViewMapUnitToRect(viewportRect)
+                    .build();
+            renderGlop(nullptr, &overdrawClip, glop);
+        }
+        mRenderState.stencil().disable();
+    }
+
+    mCaches.clearGarbage();
     mCaches.pathCache.trim();
     mCaches.tessellationCache.trim();
 
@@ -128,12 +168,121 @@
     return texture;
 }
 
-void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const Rect* clip) {
+// clears and re-fills stencil with provided rendertarget space quads,
+// and then put stencil into test mode
+void BakedOpRenderer::setupStencilQuads(std::vector<Vertex>& quadVertices,
+        int incrementThreshold) {
+    mRenderState.stencil().enableWrite(incrementThreshold);
+    mRenderState.stencil().clear();
+    Glop glop;
+    GlopBuilder(mRenderState, mCaches, &glop)
+            .setRoundRectClipState(nullptr)
+            .setMeshIndexedQuads(quadVertices.data(), quadVertices.size() / 4)
+            .setFillBlack()
+            .setTransform(Matrix4::identity(), TransformFlags::None)
+            .setModelViewIdentityEmptyBounds()
+            .build();
+    mRenderState.render(glop, mRenderTarget.orthoMatrix);
+    mRenderState.stencil().enableTest(incrementThreshold);
+}
+
+void BakedOpRenderer::setupStencilRectList(const ClipBase* clip) {
+    auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+    int quadCount = rectList.getTransformedRectanglesCount();
+    std::vector<Vertex> rectangleVertices;
+    rectangleVertices.reserve(quadCount * 4);
+    for (int i = 0; i < quadCount; i++) {
+        const TransformedRectangle& tr(rectList.getTransformedRectangle(i));
+        const Matrix4& transform = tr.getTransform();
+        Rect bounds = tr.getBounds();
+        if (transform.rectToRect()) {
+            // If rectToRect, can simply map bounds before storing verts
+            transform.mapRect(bounds);
+            bounds.doIntersect(clip->rect);
+            if (bounds.isEmpty()) {
+                continue; // will be outside of scissor, skip
+            }
+        }
+
+        rectangleVertices.push_back(Vertex{bounds.left, bounds.top});
+        rectangleVertices.push_back(Vertex{bounds.right, bounds.top});
+        rectangleVertices.push_back(Vertex{bounds.left, bounds.bottom});
+        rectangleVertices.push_back(Vertex{bounds.right, bounds.bottom});
+
+        if (!transform.rectToRect()) {
+            // If not rectToRect, must map each point individually
+            for (auto cur = rectangleVertices.end() - 4; cur < rectangleVertices.end(); cur++) {
+                transform.mapPoint(cur->x, cur->y);
+            }
+        }
+    }
+    setupStencilQuads(rectangleVertices, rectList.getTransformedRectanglesCount());
+}
+
+void BakedOpRenderer::setupStencilRegion(const ClipBase* clip) {
+    auto&& region = reinterpret_cast<const ClipRegion*>(clip)->region;
+
+    std::vector<Vertex> regionVertices;
+    SkRegion::Cliperator it(region, clip->rect.toSkIRect());
+    while (!it.done()) {
+        const SkIRect& r = it.rect();
+        regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fTop});
+        regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fTop});
+        regionVertices.push_back(Vertex{(float)r.fLeft, (float)r.fBottom});
+        regionVertices.push_back(Vertex{(float)r.fRight, (float)r.fBottom});
+        it.next();
+    }
+    setupStencilQuads(regionVertices, 0);
+}
+
+void BakedOpRenderer::prepareRender(const Rect* dirtyBounds, const ClipBase* clip) {
+    // prepare scissor / stencil
     mRenderState.scissor().setEnabled(clip != nullptr);
     if (clip) {
-        mRenderState.scissor().set(clip->left, mRenderTarget.viewportHeight - clip->bottom,
-            clip->getWidth(), clip->getHeight());
+        mRenderState.scissor().set(mRenderTarget.viewportHeight, clip->rect);
     }
+
+    if (CC_LIKELY(!Properties::debugOverdraw)) {
+        // only modify stencil mode and content when it's not used for overdraw visualization
+        if (CC_UNLIKELY(clip && clip->mode != ClipMode::Rectangle)) {
+            // NOTE: this pointer check is only safe for non-rect clips,
+            // since rect clips may be created on the stack
+            if (mRenderTarget.lastStencilClip != clip) {
+                // Stencil needed, but current stencil isn't up to date
+                mRenderTarget.lastStencilClip = clip;
+
+                if (mRenderTarget.frameBufferId != 0 && !mRenderTarget.stencil) {
+                    OffscreenBuffer* layer = mRenderTarget.offscreenBuffer;
+                    mRenderTarget.stencil = mCaches.renderBufferCache.get(
+                            Stencil::getLayerStencilFormat(),
+                            layer->texture.width, layer->texture.height);
+                    // stencil is bound + allocated - associate it with current FBO
+                    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_STENCIL_ATTACHMENT,
+                            GL_RENDERBUFFER, mRenderTarget.stencil->getName());
+                }
+
+                if (clip->mode == ClipMode::RectangleList) {
+                    setupStencilRectList(clip);
+                } else {
+                    setupStencilRegion(clip);
+                }
+            } else {
+                // stencil is up to date - just need to ensure it's enabled (since an unclipped
+                // or scissor-only clipped op may have been drawn, disabling the stencil)
+                int incrementThreshold = 0;
+                if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+                    auto&& rectList = reinterpret_cast<const ClipRectList*>(clip)->rectList;
+                    incrementThreshold = rectList.getTransformedRectanglesCount();
+                }
+                mRenderState.stencil().enableTest(incrementThreshold);
+            }
+        } else {
+            // either scissor or no clip, so disable stencil test
+            mRenderState.stencil().disable();
+        }
+    }
+
+    // dirty offscreenbuffer
     if (dirtyBounds && mRenderTarget.offscreenBuffer) {
         // register layer damage to draw-back region
         android::Rect dirty(dirtyBounds->left, dirtyBounds->top,
@@ -142,17 +291,18 @@
     }
 }
 
-void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop) {
+void BakedOpRenderer::renderGlop(const Rect* dirtyBounds, const ClipBase* clip,
+        const Glop& glop) {
     prepareRender(dirtyBounds, clip);
     mRenderState.render(glop, mRenderTarget.orthoMatrix);
     if (!mRenderTarget.frameBufferId) mHasDrawn = true;
 }
 
 void BakedOpRenderer::renderFunctor(const FunctorOp& op, const BakedOpState& state) {
-    prepareRender(&state.computedState.clippedBounds, &state.computedState.clipRect);
+    prepareRender(&state.computedState.clippedBounds, state.computedState.getClipIfNeeded());
 
     DrawGlInfo info;
-    auto&& clip = state.computedState.clipRect;
+    auto&& clip = state.computedState.clipRect();
     info.clipLeft = clip.left;
     info.clipTop = clip.top;
     info.clipRight = clip.right;
diff --git a/libs/hwui/BakedOpRenderer.h b/libs/hwui/BakedOpRenderer.h
index f158e8b..65e8b29 100644
--- a/libs/hwui/BakedOpRenderer.h
+++ b/libs/hwui/BakedOpRenderer.h
@@ -27,6 +27,7 @@
 struct Glop;
 class Layer;
 class RenderState;
+struct ClipBase;
 
 /**
  * Main rendering manager for a collection of work - one frame + any contained FBOs.
@@ -59,7 +60,7 @@
     Caches& caches() { return mCaches; }
 
     void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect);
-    void endFrame();
+    void endFrame(const Rect& repaintRect);
     OffscreenBuffer* startTemporaryLayer(uint32_t width, uint32_t height);
     void startRepaintLayer(OffscreenBuffer* offscreenBuffer, const Rect& repaintRect);
     void endLayer();
@@ -68,21 +69,23 @@
     const LightInfo& getLightInfo() const { return mLightInfo; }
 
     void renderGlop(const BakedOpState& state, const Glop& glop) {
-        bool useScissor = state.computedState.clipSideFlags != OpClipSideFlags::None;
         renderGlop(&state.computedState.clippedBounds,
-                useScissor ? &state.computedState.clipRect : nullptr,
+                state.computedState.getClipIfNeeded(),
                 glop);
     }
     void renderFunctor(const FunctorOp& op, const BakedOpState& state);
 
-    void renderGlop(const Rect* dirtyBounds, const Rect* clip, const Glop& glop);
+    void renderGlop(const Rect* dirtyBounds, const ClipBase* clip, const Glop& glop);
     bool offscreenRenderTarget() { return mRenderTarget.offscreenBuffer != nullptr; }
     void dirtyRenderTarget(const Rect& dirtyRect);
     bool didDraw() const { return mHasDrawn; }
 private:
     void setViewport(uint32_t width, uint32_t height);
     void clearColorBuffer(const Rect& clearRect);
-    void prepareRender(const Rect* dirtyBounds, const Rect* clip);
+    void prepareRender(const Rect* dirtyBounds, const ClipBase* clip);
+    void setupStencilRectList(const ClipBase* clip);
+    void setupStencilRegion(const ClipBase* clip);
+    void setupStencilQuads(std::vector<Vertex>& quadVertices, int incrementThreshold);
 
     RenderState& mRenderState;
     Caches& mCaches;
@@ -92,10 +95,23 @@
     // render target state - setup by start/end layer/frame
     // only valid to use in between start/end pairs.
     struct {
+        // If not drawing to a layer: fbo = 0, offscreenBuffer = null,
+        // Otherwise these refer to currently painting layer's state
         GLuint frameBufferId = 0;
         OffscreenBuffer* offscreenBuffer = nullptr;
+
+        // Used when drawing to a layer and using stencil clipping. otherwise null.
+        RenderBuffer* stencil = nullptr;
+
+        // value representing the ClipRectList* or ClipRegion* currently stored in
+        // the stencil of the current render target
+        const ClipBase* lastStencilClip = nullptr;
+
+        // Size of renderable region in current render target - for layers, may not match actual
+        // bounds of FBO texture. offscreenBuffer->texture has this information.
         uint32_t viewportWidth = 0;
         uint32_t viewportHeight = 0;
+
         Matrix4 orthoMatrix;
     } mRenderTarget;
 
diff --git a/libs/hwui/BakedOpState.cpp b/libs/hwui/BakedOpState.cpp
new file mode 100644
index 0000000..e6b943a
--- /dev/null
+++ b/libs/hwui/BakedOpState.cpp
@@ -0,0 +1,79 @@
+/*
+ * 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.
+ */
+
+#include "BakedOpState.h"
+
+#include "ClipArea.h"
+
+namespace android {
+namespace uirenderer {
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+        const RecordedOp& recordedOp, bool expandForStroke) {
+    // resolvedMatrix = parentMatrix * localMatrix
+    transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
+
+    // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
+    clippedBounds = recordedOp.unmappedBounds;
+    if (CC_UNLIKELY(expandForStroke)) {
+        // account for non-hairline stroke
+        clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
+    }
+    transform.mapRect(clippedBounds);
+    if (CC_UNLIKELY(expandForStroke
+            && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
+        // account for hairline stroke when stroke may be < 1 scaled pixel
+        // Non translate || strokeWidth < 1 is conservative, but will cover all cases
+        clippedBounds.outset(0.5f);
+    }
+
+    // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
+    clipState = snapshot.mutateClipArea().serializeIntersectedClip(allocator,
+            recordedOp.localClip, *(snapshot.transform));
+    LOG_ALWAYS_FATAL_IF(!clipState, "must clip!");
+
+    const Rect& clipRect = clipState->rect;
+    if (CC_UNLIKELY(clipRect.isEmpty() || !clippedBounds.intersects(clipRect))) {
+        // Rejected based on either empty clip, or bounds not intersecting with clip
+        if (clipState) {
+            allocator.rewindIfLastAlloc(clipState);
+            clipState = nullptr;
+        }
+        clippedBounds.setEmpty();
+    } else {
+        // Not rejected! compute true clippedBounds and clipSideFlags
+        if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
+        if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
+        if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
+        if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
+        clippedBounds.doIntersect(clipRect);
+    }
+}
+
+ResolvedRenderState::ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot) {
+    transform = *snapshot.transform;
+
+    // Since the op doesn't have known bounds, we conservatively set the mapped bounds
+    // to the current clipRect, and clipSideFlags to Full.
+    clipState = snapshot.mutateClipArea().serializeClip(allocator);
+    LOG_ALWAYS_FATAL_IF(!clipState, "clipState required");
+    clippedBounds = clipState->rect;
+    transform.mapRect(clippedBounds);
+    clipSideFlags = OpClipSideFlags::Full;
+}
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/BakedOpState.h b/libs/hwui/BakedOpState.h
index b12c0c9..9df4e3a 100644
--- a/libs/hwui/BakedOpState.h
+++ b/libs/hwui/BakedOpState.h
@@ -52,89 +52,35 @@
  */
 class ResolvedRenderState {
 public:
-    // TODO: remove the mapRects/matrix multiply when snapshot & recorded transforms are translates
-    ResolvedRenderState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke) {
-        /* TODO: benchmark a fast path for translate-only matrices, such as:
-        if (CC_LIKELY(snapshot.transform->getType() == Matrix4::kTypeTranslate
-                && recordedOp.localMatrix.getType() == Matrix4::kTypeTranslate)) {
-            float translateX = snapshot.transform->getTranslateX() + recordedOp.localMatrix.getTranslateX();
-            float translateY = snapshot.transform->getTranslateY() + recordedOp.localMatrix.getTranslateY();
-            transform.loadTranslate(translateX, translateY, 0);
+    ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot,
+            const RecordedOp& recordedOp, bool expandForStroke);
 
-            // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
-            clipRect = recordedOp.localClipRect;
-            clipRect.translate(translateX, translateY);
-            clipRect.doIntersect(snapshot.getClipRect());
-            clipRect.snapToPixelBoundaries();
-
-            // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
-            clippedBounds = recordedOp.unmappedBounds;
-            clippedBounds.translate(translateX, translateY);
-        } ... */
-
-        // resolvedMatrix = parentMatrix * localMatrix
-        transform.loadMultiply(*snapshot.transform, recordedOp.localMatrix);
-
-        // resolvedClipRect = intersect(parentMatrix * localClip, parentClip)
-        clipRect = recordedOp.localClipRect;
-        snapshot.transform->mapRect(clipRect);
-        clipRect.doIntersect(snapshot.getRenderTargetClip());
-        clipRect.snapToPixelBoundaries();
-
-        // resolvedClippedBounds = intersect(resolvedMatrix * opBounds, resolvedClipRect)
-        clippedBounds = recordedOp.unmappedBounds;
-        if (CC_UNLIKELY(expandForStroke)) {
-            // account for non-hairline stroke
-            clippedBounds.outset(recordedOp.paint->getStrokeWidth() * 0.5f);
-        }
-        transform.mapRect(clippedBounds);
-        if (CC_UNLIKELY(expandForStroke
-                && (!transform.isPureTranslate() || recordedOp.paint->getStrokeWidth() < 1.0f))) {
-            // account for hairline stroke when stroke may be < 1 scaled pixel
-            // Non translate || strokeWidth < 1 is conservative, but will cover all cases
-            clippedBounds.outset(0.5f);
-        }
-
-        if (clipRect.left > clippedBounds.left) clipSideFlags |= OpClipSideFlags::Left;
-        if (clipRect.top > clippedBounds.top) clipSideFlags |= OpClipSideFlags::Top;
-        if (clipRect.right < clippedBounds.right) clipSideFlags |= OpClipSideFlags::Right;
-        if (clipRect.bottom < clippedBounds.bottom) clipSideFlags |= OpClipSideFlags::Bottom;
-        clippedBounds.doIntersect(clipRect);
-
-        /**
-         * TODO: once we support complex clips, we may want to reject to avoid that work where
-         * possible. Should we:
-         * 1 - quickreject based on clippedBounds, quick early (duplicating logic in resolvedOp)
-         * 2 - merge stuff into tryConstruct factory method, so it can handle quickRejection
-         *         and early return null in one place.
-         */
-    }
-
-    /**
-     * Constructor for unbounded ops without transform/clip (namely shadows)
-     *
-     * Since the op doesn't have known bounds, we conservatively set the mapped bounds
-     * to the current clipRect, and clipSideFlags to Full.
-     */
-    ResolvedRenderState(const Snapshot& snapshot) {
-        transform = *snapshot.transform;
-        clipRect = snapshot.getRenderTargetClip();
-        clippedBounds = clipRect;
-        transform.mapRect(clippedBounds);
-        clipSideFlags = OpClipSideFlags::Full;
-    }
+    // Constructor for unbounded ops without transform/clip (namely shadows)
+    ResolvedRenderState(LinearAllocator& allocator, Snapshot& snapshot);
 
     Rect computeLocalSpaceClip() const {
         Matrix4 inverse;
         inverse.loadInverse(transform);
 
-        Rect outClip(clipRect);
+        Rect outClip(clipRect());
         inverse.mapRect(outClip);
         return outClip;
     }
 
     Matrix4 transform;
-    Rect clipRect;
+    const Rect& clipRect() const {
+        return clipState->rect;
+    }
+    bool requiresClip() const {
+        return clipSideFlags != OpClipSideFlags::None
+                || CC_UNLIKELY(clipState->mode != ClipMode::Rectangle);
+    }
+
+    // returns the clip if it's needed to draw the operation, otherwise nullptr
+    const ClipBase* getClipIfNeeded() const {
+        return requiresClip() ? clipState : nullptr;
+    }
+    const ClipBase* clipState = nullptr;
     int clipSideFlags = 0;
     Rect clippedBounds;
 };
@@ -147,8 +93,9 @@
 class BakedOpState {
 public:
     static BakedOpState* tryConstruct(LinearAllocator& allocator,
-            const Snapshot& snapshot, const RecordedOp& recordedOp) {
-        BakedOpState* bakedState = new (allocator) BakedOpState(snapshot, recordedOp, false);
+            Snapshot& snapshot, const RecordedOp& recordedOp) {
+        BakedOpState* bakedState = new (allocator) BakedOpState(
+                allocator, snapshot, recordedOp, false);
         if (bakedState->computedState.clippedBounds.isEmpty()) {
             // bounds are empty, so op is rejected
             allocator.rewindIfLastAlloc(bakedState);
@@ -165,13 +112,13 @@
     };
 
     static BakedOpState* tryStrokeableOpConstruct(LinearAllocator& allocator,
-            const Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
+            Snapshot& snapshot, const RecordedOp& recordedOp, StrokeBehavior strokeBehavior) {
         bool expandForStroke = (strokeBehavior == StrokeBehavior::StyleDefined)
                 ? (recordedOp.paint && recordedOp.paint->getStyle() != SkPaint::kFill_Style)
                 : true;
 
         BakedOpState* bakedState = new (allocator) BakedOpState(
-                snapshot, recordedOp, expandForStroke);
+                allocator, snapshot, recordedOp, expandForStroke);
         if (bakedState->computedState.clippedBounds.isEmpty()) {
             // bounds are empty, so op is rejected
             allocator.rewindIfLastAlloc(bakedState);
@@ -181,11 +128,11 @@
     }
 
     static BakedOpState* tryShadowOpConstruct(LinearAllocator& allocator,
-            const Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
+            Snapshot& snapshot, const ShadowOp* shadowOpPtr) {
         if (snapshot.getRenderTargetClip().isEmpty()) return nullptr;
 
         // clip isn't empty, so construct the op
-        return new (allocator) BakedOpState(snapshot, shadowOpPtr);
+        return new (allocator) BakedOpState(allocator, snapshot, shadowOpPtr);
     }
 
     static void* operator new(size_t size, LinearAllocator& allocator) {
@@ -202,15 +149,16 @@
     const RecordedOp* op;
 
 private:
-    BakedOpState(const Snapshot& snapshot, const RecordedOp& recordedOp, bool expandForStroke)
-            : computedState(snapshot, recordedOp, expandForStroke)
+    BakedOpState(LinearAllocator& allocator, Snapshot& snapshot,
+            const RecordedOp& recordedOp, bool expandForStroke)
+            : computedState(allocator, snapshot, recordedOp, expandForStroke)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
             , projectionPathMask(snapshot.projectionPathMask)
             , op(&recordedOp) {}
 
-    BakedOpState(const Snapshot& snapshot, const ShadowOp* shadowOpPtr)
-            : computedState(snapshot)
+    BakedOpState(LinearAllocator& allocator, Snapshot& snapshot, const ShadowOp* shadowOpPtr)
+            : computedState(allocator, snapshot)
             , alpha(snapshot.alpha)
             , roundRectClipState(snapshot.roundRectClipState)
             , projectionPathMask(snapshot.projectionPathMask)
diff --git a/libs/hwui/CanvasState.cpp b/libs/hwui/CanvasState.cpp
index cf76e6b..cf2726b 100644
--- a/libs/hwui/CanvasState.cpp
+++ b/libs/hwui/CanvasState.cpp
@@ -45,6 +45,21 @@
     }
 }
 
+void CanvasState::initializeRecordingSaveStack(int viewportWidth, int viewportHeight) {
+    if (mWidth != viewportWidth || mHeight != viewportHeight) {
+        mWidth = viewportWidth;
+        mHeight = viewportHeight;
+        mFirstSnapshot.initializeViewport(viewportWidth, viewportHeight);
+        mCanvas.onViewportInitialized();
+    }
+
+    freeAllSnapshots();
+    mSnapshot = allocSnapshot(&mFirstSnapshot,
+            SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
+    mSnapshot->setRelativeLightCenter(Vector3());
+    mSaveCount = 1;
+}
+
 void CanvasState::initializeSaveStack(
         int viewportWidth, int viewportHeight,
         float clipLeft, float clipTop,
diff --git a/libs/hwui/CanvasState.h b/libs/hwui/CanvasState.h
index 4709ef4..b9e87ae 100644
--- a/libs/hwui/CanvasState.h
+++ b/libs/hwui/CanvasState.h
@@ -80,6 +80,12 @@
      * Initializes the first snapshot, computing the projection matrix,
      * and stores the dimensions of the render target.
      */
+    void initializeRecordingSaveStack(int viewportWidth, int viewportHeight);
+
+    /**
+     * Initializes the first snapshot, computing the projection matrix,
+     * and stores the dimensions of the render target.
+     */
     void initializeSaveStack(int viewportWidth, int viewportHeight,
             float clipLeft, float clipTop, float clipRight, float clipBottom,
             const Vector3& lightCenter);
@@ -168,6 +174,7 @@
     void freeAllSnapshots();
 
     /// indicates that the clip has been changed since the last time it was consumed
+    // TODO: delete when switching to HWUI_NEW_OPS
     bool mDirtyClip;
 
     /// Dimensions of the drawing surface
diff --git a/libs/hwui/ClipArea.cpp b/libs/hwui/ClipArea.cpp
index 5f166ca..160090d 100644
--- a/libs/hwui/ClipArea.cpp
+++ b/libs/hwui/ClipArea.cpp
@@ -15,10 +15,11 @@
  */
 #include "ClipArea.h"
 
+#include "utils/LinearAllocator.h"
+
 #include <SkPath.h>
 #include <limits>
-
-#include "Rect.h"
+#include <type_traits>
 
 namespace android {
 namespace uirenderer {
@@ -171,12 +172,18 @@
     return rectangleListAsRegion;
 }
 
+void RectangleList::transform(const Matrix4& transform) {
+    for (int index = 0; index < mTransformedRectanglesCount; index++) {
+        mTransformedRectangles[index].transform(transform);
+    }
+}
+
 /*
  * ClipArea
  */
 
 ClipArea::ClipArea()
-        : mMode(Mode::Rectangle) {
+        : mMode(ClipMode::Rectangle) {
 }
 
 /*
@@ -184,39 +191,44 @@
  */
 
 void ClipArea::setViewportDimensions(int width, int height) {
+    mPostViewportClipObserved = false;
     mViewportBounds.set(0, 0, width, height);
     mClipRect = mViewportBounds;
 }
 
 void ClipArea::setEmpty() {
-    mMode = Mode::Rectangle;
+    onClipUpdated();
+    mMode = ClipMode::Rectangle;
     mClipRect.setEmpty();
     mClipRegion.setEmpty();
     mRectangleList.setEmpty();
 }
 
 void ClipArea::setClip(float left, float top, float right, float bottom) {
-    mMode = Mode::Rectangle;
+    onClipUpdated();
+    mMode = ClipMode::Rectangle;
     mClipRect.set(left, top, right, bottom);
     mClipRegion.setEmpty();
 }
 
 void ClipArea::clipRectWithTransform(const Rect& r, const mat4* transform,
         SkRegion::Op op) {
+    onClipUpdated();
     switch (mMode) {
-    case Mode::Rectangle:
+    case ClipMode::Rectangle:
         rectangleModeClipRectWithTransform(r, transform, op);
         break;
-    case Mode::RectangleList:
+    case ClipMode::RectangleList:
         rectangleListModeClipRectWithTransform(r, transform, op);
         break;
-    case Mode::Region:
+    case ClipMode::Region:
         regionModeClipRectWithTransform(r, transform, op);
         break;
     }
 }
 
 void ClipArea::clipRegion(const SkRegion& region, SkRegion::Op op) {
+    onClipUpdated();
     enterRegionMode();
     mClipRegion.op(region, op);
     onClipRegionUpdated();
@@ -224,6 +236,7 @@
 
 void ClipArea::clipPathWithTransform(const SkPath& path, const mat4* transform,
         SkRegion::Op op) {
+    onClipUpdated();
     SkMatrix skTransform;
     transform->copyTo(skTransform);
     SkPath transformed;
@@ -241,7 +254,7 @@
     // Entering rectangle mode discards any
     // existing clipping information from the other modes.
     // The only way this occurs is by a clip setting operation.
-    mMode = Mode::Rectangle;
+    mMode = ClipMode::Rectangle;
 }
 
 void ClipArea::rectangleModeClipRectWithTransform(const Rect& r,
@@ -276,8 +289,8 @@
     // Is is only legal to enter rectangle list mode from
     // rectangle mode, since rectangle list mode cannot represent
     // all clip areas that can be represented by a region.
-    ALOG_ASSERT(mMode == Mode::Rectangle);
-    mMode = Mode::RectangleList;
+    ALOG_ASSERT(mMode == ClipMode::Rectangle);
+    mMode = ClipMode::RectangleList;
     mRectangleList.set(mClipRect, Matrix4::identity());
 }
 
@@ -295,12 +308,11 @@
  */
 
 void ClipArea::enterRegionMode() {
-    Mode oldMode = mMode;
-    mMode = Mode::Region;
-    if (oldMode != Mode::Region) {
-        if (oldMode == Mode::Rectangle) {
-            mClipRegion.setRect(mClipRect.left, mClipRect.top,
-                    mClipRect.right, mClipRect.bottom);
+    ClipMode oldMode = mMode;
+    mMode = ClipMode::Region;
+    if (oldMode != ClipMode::Region) {
+        if (oldMode == ClipMode::Rectangle) {
+            mClipRegion.setRect(mClipRect.toSkIRect());
         } else {
             mClipRegion = mRectangleList.convertToRegion(createViewportRegion());
             onClipRegionUpdated();
@@ -330,5 +342,172 @@
     }
 }
 
+/**
+ * Clip serialization
+ */
+
+const ClipBase* ClipArea::serializeClip(LinearAllocator& allocator) {
+    if (!mPostViewportClipObserved) {
+        // Only initial clip-to-viewport observed, so no serialization of clip necessary
+        return nullptr;
+    }
+
+    static_assert(std::is_trivially_destructible<Rect>::value,
+            "expect Rect to be trivially destructible");
+    static_assert(std::is_trivially_destructible<RectangleList>::value,
+            "expect RectangleList to be trivially destructible");
+
+    if (mLastSerialization == nullptr) {
+        switch (mMode) {
+        case ClipMode::Rectangle:
+            mLastSerialization = allocator.create<ClipRect>(mClipRect);
+            break;
+        case ClipMode::RectangleList:
+            mLastSerialization = allocator.create<ClipRectList>(mRectangleList);
+            break;
+        case ClipMode::Region:
+            mLastSerialization = allocator.create<ClipRegion>(mClipRegion);
+            break;
+        }
+    }
+    return mLastSerialization;
+}
+
+inline static const Rect& getRect(const ClipBase* scb) {
+    return reinterpret_cast<const ClipRect*>(scb)->rect;
+}
+
+inline static const RectangleList& getRectList(const ClipBase* scb) {
+    return reinterpret_cast<const ClipRectList*>(scb)->rectList;
+}
+
+inline static const SkRegion& getRegion(const ClipBase* scb) {
+    return reinterpret_cast<const ClipRegion*>(scb)->region;
+}
+
+// Conservative check for too many rectangles to fit in rectangle list.
+// For simplicity, doesn't account for rect merging
+static bool cannotFitInRectangleList(const ClipArea& clipArea, const ClipBase* scb) {
+    int currentRectCount = clipArea.isRectangleList()
+            ? clipArea.getRectangleList().getTransformedRectanglesCount()
+            : 1;
+    int recordedRectCount = (scb->mode == ClipMode::RectangleList)
+            ? getRectList(scb).getTransformedRectanglesCount()
+            : 1;
+    return currentRectCount + recordedRectCount > RectangleList::kMaxTransformedRectangles;
+}
+
+const ClipBase* ClipArea::serializeIntersectedClip(LinearAllocator& allocator,
+        const ClipBase* recordedClip, const Matrix4& recordedClipTransform) {
+    // if no recordedClip passed, just serialize current state
+    if (!recordedClip) return serializeClip(allocator);
+
+    if (!mLastResolutionResult
+            || recordedClip != mLastResolutionClip
+            || recordedClipTransform != mLastResolutionTransform) {
+        mLastResolutionClip = recordedClip;
+        mLastResolutionTransform = recordedClipTransform;
+
+        if (CC_LIKELY(mMode == ClipMode::Rectangle
+                && recordedClip->mode == ClipMode::Rectangle
+                && recordedClipTransform.rectToRect())) {
+            // common case - result is a single rectangle
+            auto rectClip = allocator.create<ClipRect>(getRect(recordedClip));
+            recordedClipTransform.mapRect(rectClip->rect);
+            rectClip->rect.doIntersect(mClipRect);
+            mLastResolutionResult = rectClip;
+        } else if (CC_UNLIKELY(mMode == ClipMode::Region
+                || recordedClip->mode == ClipMode::Region
+                || cannotFitInRectangleList(*this, recordedClip))) {
+            // region case
+            SkRegion other;
+            switch (recordedClip->mode) {
+            case ClipMode::Rectangle:
+                if (CC_LIKELY(recordedClipTransform.rectToRect())) {
+                    // simple transform, skip creating SkPath
+                    Rect resultClip(getRect(recordedClip));
+                    recordedClipTransform.mapRect(resultClip);
+                    other.setRect(resultClip.toSkIRect());
+                } else {
+                    SkPath transformedRect = pathFromTransformedRectangle(getRect(recordedClip),
+                            recordedClipTransform);
+                    other.setPath(transformedRect, createViewportRegion());
+                }
+                break;
+            case ClipMode::RectangleList: {
+                RectangleList transformedList(getRectList(recordedClip));
+                transformedList.transform(recordedClipTransform);
+                other = transformedList.convertToRegion(createViewportRegion());
+                break;
+            }
+            case ClipMode::Region:
+                other = getRegion(recordedClip);
+
+                // TODO: handle non-translate transforms properly!
+                other.translate(recordedClipTransform.getTranslateX(),
+                        recordedClipTransform.getTranslateY());
+            }
+
+            ClipRegion* regionClip = allocator.create<ClipRegion>();
+            switch (mMode) {
+            case ClipMode::Rectangle:
+                regionClip->region.op(mClipRect.toSkIRect(), other, SkRegion::kIntersect_Op);
+                break;
+            case ClipMode::RectangleList:
+                regionClip->region.op(mRectangleList.convertToRegion(createViewportRegion()),
+                        other, SkRegion::kIntersect_Op);
+                break;
+            case ClipMode::Region:
+                regionClip->region.op(mClipRegion, other, SkRegion::kIntersect_Op);
+                break;
+            }
+            regionClip->rect.set(regionClip->region.getBounds());
+            mLastResolutionResult = regionClip;
+        } else {
+            auto rectListClip = allocator.create<ClipRectList>(mRectangleList);
+            auto&& rectList = rectListClip->rectList;
+            if (mMode == ClipMode::Rectangle) {
+                rectList.set(mClipRect, Matrix4::identity());
+            }
+
+            if (recordedClip->mode == ClipMode::Rectangle) {
+                rectList.intersectWith(getRect(recordedClip), recordedClipTransform);
+            } else {
+                const RectangleList& other = getRectList(recordedClip);
+                for (int i = 0; i < other.getTransformedRectanglesCount(); i++) {
+                    auto&& tr = other.getTransformedRectangle(i);
+                    Matrix4 totalTransform(recordedClipTransform);
+                    totalTransform.multiply(tr.getTransform());
+                    rectList.intersectWith(tr.getBounds(), totalTransform);
+                }
+            }
+            rectListClip->rect = rectList.calculateBounds();
+            mLastResolutionResult = rectListClip;
+        }
+    }
+    return mLastResolutionResult;
+}
+
+void ClipArea::applyClip(const ClipBase* clip, const Matrix4& transform) {
+    if (!clip) return; // nothing to do
+
+    if (CC_LIKELY(clip->mode == ClipMode::Rectangle)) {
+        clipRectWithTransform(getRect(clip), &transform, SkRegion::kIntersect_Op);
+    } else if (CC_LIKELY(clip->mode == ClipMode::RectangleList)) {
+        auto&& rectList = getRectList(clip);
+        for (int i = 0; i < rectList.getTransformedRectanglesCount(); i++) {
+            auto&& tr = rectList.getTransformedRectangle(i);
+            Matrix4 totalTransform(transform);
+            totalTransform.multiply(tr.getTransform());
+            clipRectWithTransform(tr.getBounds(), &totalTransform, SkRegion::kIntersect_Op);
+        }
+    } else {
+        SkRegion region(getRegion(clip));
+        // TODO: handle non-translate transforms properly!
+        region.translate(transform.getTranslateX(), transform.getTranslateY());
+        clipRegion(region, SkRegion::kIntersect_Op);
+    }
+}
+
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/ClipArea.h b/libs/hwui/ClipArea.h
index 268301c..479796d 100644
--- a/libs/hwui/ClipArea.h
+++ b/libs/hwui/ClipArea.h
@@ -16,15 +16,17 @@
 #ifndef CLIPAREA_H
 #define CLIPAREA_H
 
-#include <SkRegion.h>
-
 #include "Matrix.h"
 #include "Rect.h"
 #include "utils/Pair.h"
 
+#include <SkRegion.h>
+
 namespace android {
 namespace uirenderer {
 
+class LinearAllocator;
+
 Rect transformAndCalculateBounds(const Rect& r, const Matrix4& transform);
 
 class TransformedRectangle {
@@ -50,6 +52,12 @@
         return mTransform;
     }
 
+    void transform(const Matrix4& transform) {
+        Matrix4 t;
+        t.loadMultiply(transform, mTransform);
+        mTransform = t;
+    }
+
 private:
     Rect mBounds;
     Matrix4 mTransform;
@@ -66,27 +74,62 @@
     void setEmpty();
     void set(const Rect& bounds, const Matrix4& transform);
     bool intersectWith(const Rect& bounds, const Matrix4& transform);
+    void transform(const Matrix4& transform);
 
     SkRegion convertToRegion(const SkRegion& clip) const;
     Rect calculateBounds() const;
 
-private:
     enum {
         kMaxTransformedRectangles = 5
     };
 
+private:
     int mTransformedRectanglesCount;
     TransformedRectangle mTransformedRectangles[kMaxTransformedRectangles];
 };
 
-class ClipArea {
-private:
-    enum class Mode {
-        Rectangle,
-        Region,
-        RectangleList
-    };
+enum class ClipMode {
+    Rectangle,
+    RectangleList,
 
+    // region and path - intersected. if either is empty, don't use
+    Region
+};
+
+struct ClipBase {
+    ClipBase(ClipMode mode)
+            : mode(mode) {}
+    ClipBase(const Rect& rect)
+            : mode(ClipMode::Rectangle)
+            , rect(rect) {}
+    const ClipMode mode;
+    // Bounds of the clipping area, used to define the scissor, and define which
+    // portion of the stencil is updated/used
+    Rect rect;
+};
+
+struct ClipRect : ClipBase {
+    ClipRect(const Rect& rect)
+            : ClipBase(rect) {}
+};
+
+struct ClipRectList : ClipBase {
+    ClipRectList(const RectangleList& rectList)
+            : ClipBase(ClipMode::RectangleList)
+            , rectList(rectList) {}
+    RectangleList rectList;
+};
+
+struct ClipRegion : ClipBase {
+    ClipRegion(const SkRegion& region)
+            : ClipBase(ClipMode::Region)
+            , region(region) {}
+    ClipRegion()
+            : ClipBase(ClipMode::Region) {}
+    SkRegion region;
+};
+
+class ClipArea {
 public:
     ClipArea();
 
@@ -117,17 +160,22 @@
     }
 
     bool isRegion() const {
-        return Mode::Region == mMode;
+        return ClipMode::Region == mMode;
     }
 
     bool isSimple() const {
-        return mMode == Mode::Rectangle;
+        return mMode == ClipMode::Rectangle;
     }
 
     bool isRectangleList() const {
-        return mMode == Mode::RectangleList;
+        return mMode == ClipMode::RectangleList;
     }
 
+    const ClipBase* serializeClip(LinearAllocator& allocator);
+    const ClipBase* serializeIntersectedClip(LinearAllocator& allocator,
+            const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+    void applyClip(const ClipBase* recordedClip, const Matrix4& recordedClipTransform);
+
 private:
     void enterRectangleMode();
     void rectangleModeClipRectWithTransform(const Rect& r, const mat4* transform, SkRegion::Op op);
@@ -145,6 +193,13 @@
     void ensureClipRegion();
     void onClipRegionUpdated();
 
+    // Called by every state modifying public method.
+    void onClipUpdated() {
+        mPostViewportClipObserved = true;
+        mLastSerialization = nullptr;
+        mLastResolutionResult = nullptr;
+    }
+
     SkRegion createViewportRegion() {
         return SkRegion(mViewportBounds.toSkIRect());
     }
@@ -155,7 +210,22 @@
         pathAsRegion.setPath(path, createViewportRegion());
     }
 
-    Mode mMode;
+    ClipMode mMode;
+    bool mPostViewportClipObserved = false;
+
+    /**
+     * If mLastSerialization is non-null, it represents an already serialized copy
+     * of the current clip state. If null, it has not been computed.
+     */
+    const ClipBase* mLastSerialization = nullptr;
+
+    /**
+     * This pair of pointers is a single entry cache of most recently seen
+     */
+    const ClipBase* mLastResolutionResult = nullptr;
+    const ClipBase* mLastResolutionClip = nullptr;
+    Matrix4 mLastResolutionTransform;
+
     Rect mViewportBounds;
     Rect mClipRect;
     SkRegion mClipRegion;
diff --git a/libs/hwui/FontRenderer.h b/libs/hwui/FontRenderer.h
index ff4dc4a..9994498 100644
--- a/libs/hwui/FontRenderer.h
+++ b/libs/hwui/FontRenderer.h
@@ -47,6 +47,7 @@
 #if HWUI_NEW_OPS
 class BakedOpState;
 class BakedOpRenderer;
+struct ClipBase;
 #else
 class OpenGLRenderer;
 #endif
@@ -57,7 +58,7 @@
 #if HWUI_NEW_OPS
             BakedOpRenderer* renderer,
             const BakedOpState* bakedState,
-            const Rect* clip,
+            const ClipBase* clip,
 #else
             OpenGLRenderer* renderer,
 #endif
@@ -81,7 +82,7 @@
 #if HWUI_NEW_OPS
     BakedOpRenderer* renderer;
     const BakedOpState* bakedState;
-    const Rect* clip;
+    const ClipBase* clip;
 #else
     OpenGLRenderer* renderer;
 #endif
diff --git a/libs/hwui/Glop.h b/libs/hwui/Glop.h
index bcf819e..e72f396 100644
--- a/libs/hwui/Glop.h
+++ b/libs/hwui/Glop.h
@@ -64,7 +64,7 @@
 
         // Canvas transform isn't applied to the mesh at draw time,
         //since it's already built in.
-        MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove
+        MeshIgnoresCanvasTransform = 1 << 1, // TODO: remove for HWUI_NEW_OPS
     };
 };
 
diff --git a/libs/hwui/GlopBuilder.cpp b/libs/hwui/GlopBuilder.cpp
index 2507ff3..45fc16c 100644
--- a/libs/hwui/GlopBuilder.cpp
+++ b/libs/hwui/GlopBuilder.cpp
@@ -78,7 +78,7 @@
     mOutGlop->mesh.vertices = {
             vbo,
             VertexAttribFlags::TextureCoord,
-            nullptr, nullptr, nullptr,
+            nullptr, (const void*) kMeshTextureOffset, nullptr,
             kTextureVertexStride };
     mOutGlop->mesh.elementCount = elementCount;
     return *this;
diff --git a/libs/hwui/OpReorderer.cpp b/libs/hwui/OpReorderer.cpp
index ad9559f..11b2c8a 100644
--- a/libs/hwui/OpReorderer.cpp
+++ b/libs/hwui/OpReorderer.cpp
@@ -460,7 +460,7 @@
             deferBeginLayerOp(*new (mAllocator) BeginLayerOp(
                     saveLayerBounds,
                     Matrix4::identity(),
-                    saveLayerBounds,
+                    nullptr, // no record-time clip - need only respect defer-time one
                     &saveLayerPaint));
             deferNodeOps(node);
             deferEndLayerOp(*new (mAllocator) EndLayerOp());
@@ -604,7 +604,7 @@
             mCanvasState.getLocalClipBounds(),
             mCanvasState.currentSnapshot()->getRelativeLightCenter());
     BakedOpState* bakedOpState = BakedOpState::tryShadowOpConstruct(
-            mAllocator, *mCanvasState.currentSnapshot(), shadowOp);
+            mAllocator, *mCanvasState.writableSnapshot(), shadowOp);
     if (CC_LIKELY(bakedOpState)) {
         currentLayer().deferUnmergeableOp(mAllocator, bakedOpState, OpBatchType::Shadow);
     }
@@ -681,10 +681,10 @@
     if (op.renderNode->nothingToDraw()) return;
     int count = mCanvasState.save(SkCanvas::kClip_SaveFlag | SkCanvas::kMatrix_SaveFlag);
 
-    // apply state from RecordedOp
+    // apply state from RecordedOp (clip first, since op's clip is transformed by current matrix)
+    mCanvasState.writableSnapshot()->mutateClipArea().applyClip(op.localClip,
+            *mCanvasState.currentSnapshot()->transform);
     mCanvasState.concatMatrix(op.localMatrix);
-    mCanvasState.clipRect(op.localClipRect.left, op.localClipRect.top,
-            op.localClipRect.right, op.localClipRect.bottom, SkRegion::kIntersect_Op);
 
     // then apply state from node properties, and defer ops
     deferNodePropsAndOps(*op.renderNode);
@@ -706,7 +706,7 @@
         BakedOpState::StrokeBehavior strokeBehavior) {
     // Note: here we account for stroke when baking the op
     BakedOpState* bakedState = BakedOpState::tryStrokeableOpConstruct(
-            mAllocator, *mCanvasState.currentSnapshot(), op, strokeBehavior);
+            mAllocator, *mCanvasState.writableSnapshot(), op, strokeBehavior);
     if (!bakedState) return; // quick rejected
     currentLayer().deferUnmergeableOp(mAllocator, bakedState, batchId);
 }
@@ -769,7 +769,7 @@
     const OvalOp* resolvedOp = new (mAllocator) OvalOp(
             unmappedBounds,
             op.localMatrix,
-            op.localClipRect,
+            op.localClip,
             op.paint);
     deferOvalOp(*resolvedOp);
 }
@@ -829,7 +829,7 @@
     const RoundRectOp* resolvedOp = new (mAllocator) RoundRectOp(
             Rect(*(op.left), *(op.top), *(op.right), *(op.bottom)),
             op.localMatrix,
-            op.localClipRect,
+            op.localClip,
             op.paint, *op.rx, *op.ry);
     deferRoundRectOp(*resolvedOp);
 }
@@ -953,7 +953,7 @@
     LayerOp* drawLayerOp = new (mAllocator) LayerOp(
             beginLayerOp.unmappedBounds,
             beginLayerOp.localMatrix,
-            beginLayerOp.localClipRect,
+            beginLayerOp.localClip,
             beginLayerOp.paint,
             &mLayerReorderers[finishedLayerIndex].offscreenBuffer);
     BakedOpState* bakedOpState = tryBakeOpState(*drawLayerOp);
diff --git a/libs/hwui/OpReorderer.h b/libs/hwui/OpReorderer.h
index dbbce8b..4e9b5e6 100644
--- a/libs/hwui/OpReorderer.h
+++ b/libs/hwui/OpReorderer.h
@@ -192,7 +192,7 @@
         const LayerReorderer& fbo0 = mLayerReorderers[0];
         renderer.startFrame(fbo0.width, fbo0.height, fbo0.repaintRect);
         fbo0.replayBakedOpsImpl((void*)&renderer, unmergedReceivers, mergedReceivers);
-        renderer.endFrame();
+        renderer.endFrame(fbo0.repaintRect);
     }
 
     void dump() const {
@@ -223,7 +223,7 @@
     LayerReorderer& currentLayer() { return mLayerReorderers[mLayerStack.back()]; }
 
     BakedOpState* tryBakeOpState(const RecordedOp& recordedOp) {
-        return BakedOpState::tryConstruct(mAllocator, *mCanvasState.currentSnapshot(), recordedOp);
+        return BakedOpState::tryConstruct(mAllocator, *mCanvasState.writableSnapshot(), recordedOp);
     }
 
     // should always be surrounded by a save/restore pair, and not called if DisplayList is null
diff --git a/libs/hwui/RecordedOp.h b/libs/hwui/RecordedOp.h
index cfdd0d2..1971530 100644
--- a/libs/hwui/RecordedOp.h
+++ b/libs/hwui/RecordedOp.h
@@ -33,6 +33,7 @@
 namespace android {
 namespace uirenderer {
 
+struct ClipBase;
 class OffscreenBuffer;
 class RenderNode;
 struct Vertex;
@@ -91,10 +92,10 @@
 static_assert(RecordedOpId::ArcOp == 0,
         "First index must be zero for LUTs to work");
 
-#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint
-#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const Rect& localClipRect
-#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, paint)
-#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClipRect, nullptr)
+#define BASE_PARAMS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint
+#define BASE_PARAMS_PAINTLESS const Rect& unmappedBounds, const Matrix4& localMatrix, const ClipBase* localClip
+#define SUPER(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, paint)
+#define SUPER_PAINTLESS(Type) RecordedOp(RecordedOpId::Type, unmappedBounds, localMatrix, localClip, nullptr)
 
 struct RecordedOp {
     /* ID from RecordedOpId - generally used for jumping into function tables */
@@ -106,8 +107,8 @@
     /* transform in recording space (vs DisplayList origin) */
     const Matrix4 localMatrix;
 
-    /* clip in recording space */
-    const Rect localClipRect;
+    /* clip in recording space - nullptr if not clipped */
+    const ClipBase* localClip;
 
     /* optional paint, stored in base object to simplify merging logic */
     const SkPaint* paint;
@@ -116,7 +117,7 @@
             : opId(opId)
             , unmappedBounds(unmappedBounds)
             , localMatrix(localMatrix)
-            , localClipRect(localClipRect)
+            , localClip(localClip)
             , paint(paint) {}
 };
 
@@ -187,9 +188,9 @@
 };
 
 struct CirclePropsOp : RecordedOp {
-    CirclePropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+    CirclePropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
             float* x, float* y, float* radius)
-            : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClipRect, paint)
+            : RecordedOp(RecordedOpId::CirclePropsOp, Rect(), localMatrix, localClip, paint)
             , x(x)
             , y(y)
             , radius(radius) {}
@@ -259,9 +260,9 @@
 };
 
 struct RoundRectPropsOp : RecordedOp {
-    RoundRectPropsOp(const Matrix4& localMatrix, const Rect& localClipRect, const SkPaint* paint,
+    RoundRectPropsOp(const Matrix4& localMatrix, const ClipBase* localClip, const SkPaint* paint,
             float* left, float* top, float* right, float* bottom, float *rx, float *ry)
-            : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClipRect, paint)
+            : RecordedOp(RecordedOpId::RoundRectPropsOp, Rect(), localMatrix, localClip, paint)
             , left(left)
             , top(top)
             , right(right)
@@ -286,12 +287,13 @@
  */
 struct ShadowOp : RecordedOp {
     ShadowOp(const RenderNodeOp& casterOp, float casterAlpha, const SkPath* casterPath,
-            const Rect& clipRect, const Vector3& lightCenter)
-            : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), clipRect, nullptr)
+            const Rect& localClipRect, const Vector3& lightCenter)
+            : RecordedOp(RecordedOpId::ShadowOp, Rect(), Matrix4::identity(), nullptr, nullptr)
             , shadowMatrixXY(casterOp.localMatrix)
             , shadowMatrixZ(casterOp.localMatrix)
             , casterAlpha(casterAlpha)
             , casterPath(casterPath)
+            , localClipRect(localClipRect)
             , lightCenter(lightCenter) {
         const RenderNode& node = *casterOp.renderNode;
         node.applyViewPropertyTransforms(shadowMatrixXY, false);
@@ -301,6 +303,7 @@
     Matrix4 shadowMatrixZ;
     const float casterAlpha;
     const SkPath* casterPath;
+    const Rect localClipRect;
     const Vector3 lightCenter;
 };
 
@@ -374,7 +377,7 @@
  */
 struct EndLayerOp : RecordedOp {
     EndLayerOp()
-            : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), Rect(), nullptr) {}
+            : RecordedOp(RecordedOpId::EndLayerOp, Rect(), Matrix4::identity(), nullptr, nullptr) {}
 };
 
 /**
@@ -388,13 +391,13 @@
     LayerOp(BASE_PARAMS, OffscreenBuffer** layerHandle)
             : SUPER_PAINTLESS(LayerOp)
             , layerHandle(layerHandle)
-            , alpha(paint->getAlpha() / 255.0f)
+            , alpha(paint ? paint->getAlpha() / 255.0f : 1.0f)
             , mode(PaintUtils::getXfermodeDirect(paint))
-            , colorFilter(paint->getColorFilter())
+            , colorFilter(paint ? paint->getColorFilter() : nullptr)
             , destroy(true) {}
 
     LayerOp(RenderNode& node)
-        : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), Rect(node.getWidth(), node.getHeight()), nullptr)
+        : RecordedOp(RecordedOpId::LayerOp, Rect(node.getWidth(), node.getHeight()), Matrix4::identity(), nullptr, nullptr)
         , layerHandle(node.getLayerHandle())
         , alpha(node.properties().layerProperties().alpha() / 255.0f)
         , mode(node.properties().layerProperties().xferMode())
diff --git a/libs/hwui/RecordingCanvas.cpp b/libs/hwui/RecordingCanvas.cpp
index f75d8d4..f7f6caf 100644
--- a/libs/hwui/RecordingCanvas.cpp
+++ b/libs/hwui/RecordingCanvas.cpp
@@ -39,7 +39,7 @@
             "prepareDirty called a second time during a recording!");
     mDisplayList = new DisplayList();
 
-    mState.initializeSaveStack(width, height, 0, 0, width, height, Vector3());
+    mState.initializeRecordingSaveStack(width, height);
 
     mDeferredBarrierType = DeferredBarrierType::InOrder;
     mState.setDirtyClip(false);
@@ -155,6 +155,8 @@
         return saveValue;
     }
 
+    auto previousClip = getRecordedClip(); // note: done while snapshot == previous
+
     snapshot.flags |= Snapshot::kFlagFboTarget | Snapshot::kFlagIsFboLayer;
     snapshot.initializeViewport(untransformedBounds.getWidth(), untransformedBounds.getHeight());
     snapshot.transform->loadTranslate(-untransformedBounds.left, -untransformedBounds.top, 0.0f);
@@ -167,7 +169,7 @@
     addOp(new (alloc()) BeginLayerOp(
             Rect(left, top, right, bottom),
             *previous.transform, // transform to *draw* with
-            previous.getRenderTargetClip(), // clip to *draw* with
+            previousClip, // clip to *draw* with
             refPaint(paint)));
 
     return saveValue;
@@ -229,11 +231,10 @@
 }
 
 void RecordingCanvas::drawPaint(const SkPaint& paint) {
-    // TODO: more efficient recording?
     addOp(new (alloc()) RectOp(
-            mState.getRenderTargetClipBounds(),
+            mState.getRenderTargetClipBounds(), // OK, since we've not passed transform
             Matrix4::identity(),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint)));
 }
 
@@ -253,7 +254,7 @@
     addOp(new (alloc()) PointsOp(
             calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
 }
 
@@ -264,7 +265,7 @@
     addOp(new (alloc()) LinesOp(
             calcBoundsOfPoints(points, floatCount),
             *mState.currentSnapshot()->transform,
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), refBuffer<float>(points, floatCount), floatCount));
 }
 
@@ -272,7 +273,7 @@
     addOp(new (alloc()) RectOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint)));
 }
 
@@ -305,7 +306,7 @@
     addOp(new (alloc()) SimpleRectsOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), rectData, vertexCount));
 }
 
@@ -339,7 +340,7 @@
     addOp(new (alloc()) RoundRectOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), rx, ry));
 }
 
@@ -358,7 +359,7 @@
     refBitmapsInShader(paint->value.getShader());
     addOp(new (alloc()) RoundRectPropsOp(
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             &paint->value,
             &left->value, &top->value, &right->value, &bottom->value,
             &rx->value, &ry->value));
@@ -380,7 +381,7 @@
     refBitmapsInShader(paint->value.getShader());
     addOp(new (alloc()) CirclePropsOp(
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             &paint->value,
             &x->value, &y->value, &radius->value));
 }
@@ -390,7 +391,7 @@
     addOp(new (alloc()) OvalOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint)));
 }
 
@@ -399,7 +400,7 @@
     addOp(new (alloc()) ArcOp(
             Rect(left, top, right, bottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint),
             startAngle, sweepAngle, useCenter));
 }
@@ -408,7 +409,7 @@
     addOp(new (alloc()) PathOp(
             Rect(path.getBounds()),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), refPath(&path)));
 }
 
@@ -459,7 +460,7 @@
         addOp(new (alloc()) BitmapRectOp(
                 Rect(dstLeft, dstTop, dstRight, dstBottom),
                 *(mState.currentSnapshot()->transform),
-                mState.getRenderTargetClipBounds(),
+                getRecordedClip(),
                 refPaint(paint), refBitmap(bitmap),
                 Rect(srcLeft, srcTop, srcRight, srcBottom)));
     }
@@ -471,7 +472,7 @@
     addOp(new (alloc()) BitmapMeshOp(
             calcBoundsOfPoints(vertices, vertexCount * 2),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), refBitmap(bitmap), meshWidth, meshHeight,
             refBuffer<float>(vertices, vertexCount * 2), // 2 floats per vertex
             refBuffer<int>(colors, vertexCount))); // 1 color per vertex
@@ -483,7 +484,7 @@
     addOp(new (alloc()) PatchOp(
             Rect(dstLeft, dstTop, dstRight, dstBottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), refBitmap(bitmap), refPatch(&patch)));
 }
 
@@ -499,7 +500,7 @@
     addOp(new (alloc()) TextOp(
             Rect(boundsLeft, boundsTop, boundsRight, boundsBottom),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), glyphs, positions, glyphCount, x, y));
     drawTextDecorations(x, y, totalAdvance, paint);
 }
@@ -509,9 +510,9 @@
     if (!glyphs || glyphCount <= 0 || PaintUtils::paintWillNotDrawText(paint)) return;
     glyphs = refBuffer<glyph_t>(glyphs, glyphCount);
     addOp(new (alloc()) TextOnPathOp(
-            mState.getRenderTargetClipBounds(), // TODO: explicitly define bounds
+            mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(&paint), glyphs, glyphCount, refPath(&path), hOffset, vOffset));
 }
 
@@ -519,7 +520,7 @@
     addOp(new (alloc()) BitmapOp(
             Rect(bitmap->width(), bitmap->height()),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             refPaint(paint), refBitmap(*bitmap)));
 }
 
@@ -528,7 +529,7 @@
     RenderNodeOp* op = new (alloc()) RenderNodeOp(
             Rect(stagingProps.getWidth(), stagingProps.getHeight()),
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             renderNode);
     int opIndex = addOp(op);
     int childIndex = mDisplayList->addChild(op);
@@ -554,16 +555,16 @@
     addOp(new (alloc()) TextureLayerOp(
             Rect(layer->getWidth(), layer->getHeight()),
             totalTransform,
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             layer));
 }
 
 void RecordingCanvas::callDrawGLFunction(Functor* functor) {
     mDisplayList->functors.push_back(functor);
     addOp(new (alloc()) FunctorOp(
-            mState.getRenderTargetClipBounds(), // TODO: explicitly define bounds
+            mState.getLocalClipBounds(), // TODO: explicitly define bounds
             *(mState.currentSnapshot()->transform),
-            mState.getRenderTargetClipBounds(),
+            getRecordedClip(),
             functor));
 }
 
diff --git a/libs/hwui/RecordingCanvas.h b/libs/hwui/RecordingCanvas.h
index 470f9ec..1a2ac97f 100644
--- a/libs/hwui/RecordingCanvas.h
+++ b/libs/hwui/RecordingCanvas.h
@@ -36,6 +36,7 @@
 namespace android {
 namespace uirenderer {
 
+struct ClipBase;
 class DeferredLayerUpdater;
 struct RecordedOp;
 
@@ -199,6 +200,9 @@
     virtual bool drawTextAbsolutePos() const override { return false; }
 
 private:
+    const ClipBase* getRecordedClip() {
+        return mState.writableSnapshot()->mutateClipArea().serializeClip(alloc());
+    }
 
     void drawBitmap(const SkBitmap* bitmap, const SkPaint* paint);
     void drawSimpleRects(const float* rects, int vertexCount, const SkPaint* paint);
diff --git a/libs/hwui/Snapshot.h b/libs/hwui/Snapshot.h
index 194aa57..5fac3a1 100644
--- a/libs/hwui/Snapshot.h
+++ b/libs/hwui/Snapshot.h
@@ -167,6 +167,7 @@
     const SkRegion& getClipRegion() const { return mClipArea->getClipRegion(); }
     bool clipIsSimple() const { return mClipArea->isSimple(); }
     const ClipArea& getClipArea() const { return *mClipArea; }
+    ClipArea& mutateClipArea() { return *mClipArea; }
 
     /**
      * Resets the clip to the specified rect.
diff --git a/libs/hwui/renderstate/Scissor.cpp b/libs/hwui/renderstate/Scissor.cpp
index 95dcd18..61dd8c3 100644
--- a/libs/hwui/renderstate/Scissor.cpp
+++ b/libs/hwui/renderstate/Scissor.cpp
@@ -15,6 +15,8 @@
  */
 #include "renderstate/Scissor.h"
 
+#include "Rect.h"
+
 #include <utils/Log.h>
 
 namespace android {
@@ -71,6 +73,26 @@
     return false;
 }
 
+void Scissor::set(int viewportHeight, const Rect& clip) {
+    // transform to Y-flipped GL space, and prevent negatives
+    GLint x = std::max(0, (int)clip.left);
+    GLint y = std::max(0, viewportHeight - (int)clip.bottom);
+    GLint width = std::max(0, ((int)clip.right) - x);
+    GLint height = std::max(0, (viewportHeight - (int)clip.top) - y);
+
+    if (x != mScissorX
+            || y != mScissorY
+            || width != mScissorWidth
+            || height != mScissorHeight) {
+        glScissor(x, y, width, height);
+
+        mScissorX = x;
+        mScissorY = y;
+        mScissorWidth = width;
+        mScissorHeight = height;
+    }
+}
+
 void Scissor::reset() {
     mScissorX = mScissorY = mScissorWidth = mScissorHeight = 0;
 }
diff --git a/libs/hwui/renderstate/Scissor.h b/libs/hwui/renderstate/Scissor.h
index b37ec58..f302244 100644
--- a/libs/hwui/renderstate/Scissor.h
+++ b/libs/hwui/renderstate/Scissor.h
@@ -22,11 +22,14 @@
 namespace android {
 namespace uirenderer {
 
+class Rect;
+
 class Scissor {
     friend class RenderState;
 public:
     bool setEnabled(bool enabled);
     bool set(GLint x, GLint y, GLint width, GLint height);
+    void set(int viewportHeight, const Rect& clip);
     void reset();
     bool isEnabled() { return mEnabled; }
     void dump();
diff --git a/libs/hwui/tests/common/scenes/ClippingAnimation.cpp b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
new file mode 100644
index 0000000..db6402c
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/ClippingAnimation.cpp
@@ -0,0 +1,67 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+
+class ClippingAnimation;
+
+static TestScene::Registrar _RectGrid(TestScene::Info{
+    "clip",
+    "Complex clip cases"
+    "Low CPU/GPU load.",
+    TestScene::simpleCreateScene<ClippingAnimation>
+});
+
+class ClippingAnimation : public TestScene {
+public:
+    sp<RenderNode> card;
+    void createContent(int width, int height, TestCanvas& canvas) override {
+        canvas.drawColor(Color::White, SkXfermode::kSrcOver_Mode);
+        card = TestUtils::createNode(0, 0, 200, 400,
+                [](RenderProperties& props, TestCanvas& canvas) {
+            canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+            {
+                canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+                canvas.translate(100, 100);
+                canvas.rotate(45);
+                canvas.translate(-100, -100);
+                canvas.clipRect(0, 0, 200, 200, SkRegion::kIntersect_Op);
+                canvas.drawColor(Color::Blue_500, SkXfermode::kSrcOver_Mode);
+            }
+            canvas.restore();
+
+            canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+            {
+                SkPath clipCircle;
+                clipCircle.addCircle(100, 300, 100);
+                canvas.clipPath(&clipCircle, SkRegion::kIntersect_Op);
+                canvas.drawColor(Color::Red_500, SkXfermode::kSrcOver_Mode);
+            }
+            canvas.restore();
+
+            // put on a layer, to test stencil attachment
+            props.mutateLayerProperties().setType(LayerType::RenderLayer);
+            props.setAlpha(0.9f);
+        });
+        canvas.drawRenderNode(card.get());
+    }
+    void doFrame(int frameNr) override {
+        int curFrame = frameNr % 150;
+        card->mutateStagingProperties().setTranslationX(curFrame);
+        card->mutateStagingProperties().setTranslationY(curFrame);
+        card->setPropertyFieldsDirty(RenderNode::X | RenderNode::Y);
+    }
+};
diff --git a/libs/hwui/tests/common/scenes/TestSceneBase.h b/libs/hwui/tests/common/scenes/TestSceneBase.h
index ac78124..935ddcf 100644
--- a/libs/hwui/tests/common/scenes/TestSceneBase.h
+++ b/libs/hwui/tests/common/scenes/TestSceneBase.h
@@ -22,6 +22,7 @@
 #include "tests/common/TestContext.h"
 #include "tests/common/TestScene.h"
 #include "tests/common/TestUtils.h"
+#include "utils/Color.h"
 
 #include <functional>
 
diff --git a/libs/hwui/tests/unit/BakedOpStateTests.cpp b/libs/hwui/tests/unit/BakedOpStateTests.cpp
index f9f5316..3fd822d 100644
--- a/libs/hwui/tests/unit/BakedOpStateTests.cpp
+++ b/libs/hwui/tests/unit/BakedOpStateTests.cpp
@@ -17,6 +17,7 @@
 #include <gtest/gtest.h>
 
 #include <BakedOpState.h>
+#include <ClipArea.h>
 #include <RecordedOp.h>
 #include <tests/common/TestUtils.h>
 
@@ -24,31 +25,33 @@
 namespace uirenderer {
 
 TEST(ResolvedRenderState, construct) {
+    LinearAllocator allocator;
     Matrix4 translate10x20;
     translate10x20.loadTranslate(10, 20, 0);
 
     SkPaint paint;
-    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, Rect(100, 200), &paint);
+    ClipRect clip(Rect(100, 200));
+    RectOp recordedOp(Rect(30, 40, 100, 200), translate10x20, &clip, &paint);
     {
         // recorded with transform, no parent transform
         auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
         EXPECT_MATRIX_APPROX_EQ(state.transform, translate10x20);
-        EXPECT_EQ(Rect(100, 200), state.clipRect);
+        EXPECT_EQ(Rect(100, 200), state.clipRect());
         EXPECT_EQ(Rect(40, 60, 100, 200), state.clippedBounds); // translated and also clipped
         EXPECT_EQ(OpClipSideFlags::Right | OpClipSideFlags::Bottom, state.clipSideFlags);
     }
     {
         // recorded with transform and parent transform
         auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
 
         Matrix4 expectedTranslate;
         expectedTranslate.loadTranslate(20, 40, 0);
         EXPECT_MATRIX_APPROX_EQ(expectedTranslate, state.transform);
 
         // intersection of parent & transformed child clip
-        EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect);
+        EXPECT_EQ(Rect(10, 20, 100, 200), state.clipRect());
 
         // translated and also clipped
         EXPECT_EQ(Rect(50, 80, 100, 200), state.clippedBounds);
@@ -57,22 +60,24 @@
 }
 
 TEST(ResolvedRenderState, computeLocalSpaceClip) {
+    LinearAllocator allocator;
     Matrix4 translate10x20;
     translate10x20.loadTranslate(10, 20, 0);
 
     SkPaint paint;
-    RectOp recordedOp(Rect(1000, 1000), translate10x20, Rect(100, 200), &paint);
+    ClipRect clip(Rect(100, 200));
+    RectOp recordedOp(Rect(1000, 1000), translate10x20, &clip, &paint);
     {
         // recorded with transform, no parent transform
         auto parentSnapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
         EXPECT_EQ(Rect(-10, -20, 90, 180), state.computeLocalSpaceClip())
             << "Local clip rect should be 100x200, offset by -10,-20";
     }
     {
         // recorded with transform + parent transform
         auto parentSnapshot = TestUtils::makeSnapshot(translate10x20, Rect(100, 200));
-        ResolvedRenderState state(*parentSnapshot, recordedOp, false);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, false);
         EXPECT_EQ(Rect(-10, -20, 80, 160), state.computeLocalSpaceClip())
             << "Local clip rect should be 90x190, offset by -10,-20";
     }
@@ -149,6 +154,7 @@
 };
 
 TEST(ResolvedRenderState, construct_expandForStroke) {
+    LinearAllocator allocator;
     // Loop over table of test cases and verify different combinations of stroke width and transform
     for (auto&& testCase : sStrokeTestCases) {
         SkPaint strokedPaint;
@@ -156,14 +162,15 @@
         strokedPaint.setStyle(SkPaint::kStroke_Style);
         strokedPaint.setStrokeWidth(testCase.strokeWidth);
 
+        ClipRect clip(Rect(200, 200));
         RectOp recordedOp(Rect(50, 50, 150, 150),
-                Matrix4::identity(), Rect(200, 200), &strokedPaint);
+                Matrix4::identity(), &clip, &strokedPaint);
 
         Matrix4 snapshotMatrix;
         snapshotMatrix.loadScale(testCase.scale, testCase.scale, 1);
         auto parentSnapshot = TestUtils::makeSnapshot(snapshotMatrix, Rect(200, 200));
 
-        ResolvedRenderState state(*parentSnapshot, recordedOp, true);
+        ResolvedRenderState state(allocator, *parentSnapshot, recordedOp, true);
         testCase.validator(state);
     }
 }
@@ -175,8 +182,9 @@
     translate100x0.loadTranslate(100, 0, 0);
 
     SkPaint paint;
+    ClipRect clip(Rect(100, 200));
     {
-        RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, Rect(100, 200), &paint);
+        RectOp rejectOp(Rect(30, 40, 100, 200), translate100x0, &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
         BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, rejectOp);
 
@@ -184,7 +192,7 @@
         EXPECT_GT(8u, allocator.usedSize()); // no significant allocation space used for rejected op
     }
     {
-        RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+        RectOp successOp(Rect(30, 40, 100, 200), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(100, 200));
         BakedOpState* bakedState = BakedOpState::tryConstruct(allocator, *snapshot, successOp);
 
@@ -218,7 +226,8 @@
         SkPaint paint;
         paint.setStyle(SkPaint::kStrokeAndFill_Style);
         paint.setStrokeWidth(0.0f);
-        RectOp rejectOp(Rect(100, 200), Matrix4::identity(), Rect(100, 200), &paint);
+        ClipRect clip(Rect(100, 200));
+        RectOp rejectOp(Rect(100, 200), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect()); // Note: empty clip
         auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
                 BakedOpState::StrokeBehavior::StyleDefined);
@@ -231,7 +240,8 @@
         SkPaint paint;
         paint.setStyle(SkPaint::kStrokeAndFill_Style);
         paint.setStrokeWidth(10.0f);
-        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+        ClipRect clip(Rect(200, 200));
+        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
         auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
                 BakedOpState::StrokeBehavior::StyleDefined);
@@ -245,7 +255,8 @@
         SkPaint paint;
         paint.setStyle(SkPaint::kFill_Style);
         paint.setStrokeWidth(10.0f);
-        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), Rect(200, 200), &paint);
+        ClipRect clip(Rect(200, 200));
+        RectOp rejectOp(Rect(50, 50, 150, 150), Matrix4::identity(), &clip, &paint);
         auto snapshot = TestUtils::makeSnapshot(Matrix4::identity(), Rect(200, 200));
         auto bakedState = BakedOpState::tryStrokeableOpConstruct(allocator, *snapshot, rejectOp,
                 BakedOpState::StrokeBehavior::Forced);
diff --git a/libs/hwui/tests/unit/ClipAreaTests.cpp b/libs/hwui/tests/unit/ClipAreaTests.cpp
index c4d305e..4cae737 100644
--- a/libs/hwui/tests/unit/ClipAreaTests.cpp
+++ b/libs/hwui/tests/unit/ClipAreaTests.cpp
@@ -119,5 +119,122 @@
     EXPECT_EQ(expected, area.getClipRect());
 }
 
+TEST(ClipArea, serializeClip) {
+    ClipArea area(createClipArea());
+    LinearAllocator allocator;
+
+    // unset clip
+    EXPECT_EQ(nullptr, area.serializeClip(allocator));
+
+    // rect clip
+    area.setClip(0, 0, 200, 200);
+    {
+        auto serializedClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, serializedClip);
+        ASSERT_EQ(ClipMode::Rectangle, serializedClip->mode);
+        auto clipRect = reinterpret_cast<const ClipRect*>(serializedClip);
+        ASSERT_EQ(Rect(200, 200), clipRect->rect);
+        EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+                << "Requery of clip on unmodified ClipArea must return same pointer.";
+    }
+
+    // rect list
+    Matrix4 rotate;
+    rotate.loadRotate(2.0f);
+    area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+    {
+        auto serializedClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, serializedClip);
+        ASSERT_EQ(ClipMode::RectangleList, serializedClip->mode);
+        auto clipRectList = reinterpret_cast<const ClipRectList*>(serializedClip);
+        ASSERT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+        EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+                << "Requery of clip on unmodified ClipArea must return same pointer.";
+    }
+
+    // region
+    SkPath circlePath;
+    circlePath.addCircle(100, 100, 100);
+    area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+    {
+        auto serializedClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, serializedClip);
+        ASSERT_EQ(ClipMode::Region, serializedClip->mode);
+        auto clipRegion = reinterpret_cast<const ClipRegion*>(serializedClip);
+        ASSERT_EQ(SkIRect::MakeWH(200, 200), clipRegion->region.getBounds())
+                << "Clip region should be 200x200";
+        EXPECT_EQ(serializedClip, area.serializeClip(allocator))
+                << "Requery of clip on unmodified ClipArea must return same pointer.";
+    }
 }
+
+TEST(ClipArea, serializeIntersectedClip) {
+    ClipArea area(createClipArea());
+    LinearAllocator allocator;
+
+    // simple state;
+    EXPECT_EQ(nullptr, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+    area.setClip(0, 0, 200, 200);
+    {
+        auto origRectClip = area.serializeClip(allocator);
+        ASSERT_NE(nullptr, origRectClip);
+        EXPECT_EQ(origRectClip, area.serializeIntersectedClip(allocator, nullptr, Matrix4::identity()));
+    }
+
+    // rect
+    {
+        ClipRect recordedClip(Rect(100, 100));
+        Matrix4 translateScale;
+        translateScale.loadTranslate(100, 100, 0);
+        translateScale.scale(2, 3, 1);
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, translateScale);
+        ASSERT_NE(nullptr, resolvedClip);
+        ASSERT_EQ(ClipMode::Rectangle, resolvedClip->mode);
+        EXPECT_EQ(Rect(100, 100, 200, 200),
+                reinterpret_cast<const ClipRect*>(resolvedClip)->rect);
+
+        EXPECT_EQ(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip, translateScale))
+                << "Must return previous serialization, since input is same";
+
+        ClipRect recordedClip2(Rect(100, 100));
+        EXPECT_NE(resolvedClip, area.serializeIntersectedClip(allocator, &recordedClip2, translateScale))
+                << "Shouldn't return previous serialization, since matrix location is different";
+    }
+
+    // rect list
+    Matrix4 rotate;
+    rotate.loadRotate(2.0f);
+    area.clipRectWithTransform(Rect(200, 200), &rotate, SkRegion::kIntersect_Op);
+    {
+        ClipRect recordedClip(Rect(100, 100));
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip, Matrix4::identity());
+        ASSERT_NE(nullptr, resolvedClip);
+        ASSERT_EQ(ClipMode::RectangleList, resolvedClip->mode);
+        auto clipRectList = reinterpret_cast<const ClipRectList*>(resolvedClip);
+        EXPECT_EQ(2, clipRectList->rectList.getTransformedRectanglesCount());
+    }
+
+    // region
+    SkPath circlePath;
+    circlePath.addCircle(100, 100, 100);
+    area.clipPathWithTransform(circlePath, &Matrix4::identity(), SkRegion::kReplace_Op);
+    {
+        SkPath ovalPath;
+        ovalPath.addOval(SkRect::MakeLTRB(50, 0, 150, 200));
+
+        ClipRegion recordedClip;
+        recordedClip.region.setPath(ovalPath, SkRegion(SkIRect::MakeWH(200, 200)));
+
+        Matrix4 translate10x20;
+        translate10x20.loadTranslate(10, 20, 0);
+        auto resolvedClip = area.serializeIntersectedClip(allocator, &recordedClip,
+                translate10x20); // Note: only translate for now, others not handled correctly
+        ASSERT_NE(nullptr, resolvedClip);
+        ASSERT_EQ(ClipMode::Region, resolvedClip->mode);
+        auto clipRegion = reinterpret_cast<const ClipRegion*>(resolvedClip);
+        EXPECT_EQ(SkIRect::MakeLTRB(60, 20, 160, 200), clipRegion->region.getBounds());
+    }
 }
+
+} // namespace uirenderer
+} // namespace android
diff --git a/libs/hwui/tests/unit/LinearAllocatorTests.cpp b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
index 78d65dd..5c44290 100644
--- a/libs/hwui/tests/unit/LinearAllocatorTests.cpp
+++ b/libs/hwui/tests/unit/LinearAllocatorTests.cpp
@@ -27,7 +27,7 @@
     int two = 2;
 };
 
-TEST(LinearAllocator, alloc) {
+TEST(LinearAllocator, create) {
     LinearAllocator la;
     EXPECT_EQ(0u, la.usedSize());
     la.alloc(64);
@@ -35,7 +35,7 @@
     // so the usedSize isn't strictly defined
     EXPECT_LE(64u, la.usedSize());
     EXPECT_GT(80u, la.usedSize());
-    auto pair = la.alloc<SimplePair>();
+    auto pair = la.create<SimplePair>();
     EXPECT_LE(64u + sizeof(SimplePair), la.usedSize());
     EXPECT_GT(80u + sizeof(SimplePair), la.usedSize());
     EXPECT_EQ(1, pair->one);
@@ -47,8 +47,8 @@
     {
         LinearAllocator la;
         for (int i = 0; i < 5; i++) {
-            la.alloc<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
-            la.alloc<SimplePair>();
+            la.create<TestUtils::SignalingDtor>()->setSignal(destroyed + i);
+            la.create<SimplePair>();
         }
         la.alloc(100);
         for (int i = 0; i < 5; i++) {
@@ -75,7 +75,7 @@
         la.rewindIfLastAlloc(addr, 100);
         EXPECT_GT(16u, la.usedSize());
         size_t emptySize = la.usedSize();
-        auto sigdtor = la.alloc<TestUtils::SignalingDtor>();
+        auto sigdtor = la.create<TestUtils::SignalingDtor>();
         sigdtor->setSignal(&destroyed);
         EXPECT_EQ(0, destroyed);
         EXPECT_LE(emptySize, la.usedSize());
diff --git a/libs/hwui/tests/unit/OpReordererTests.cpp b/libs/hwui/tests/unit/OpReordererTests.cpp
index b28e436..0d13118 100644
--- a/libs/hwui/tests/unit/OpReordererTests.cpp
+++ b/libs/hwui/tests/unit/OpReordererTests.cpp
@@ -64,7 +64,7 @@
         ADD_FAILURE() << "Layer updates not expected in this test";
     }
     virtual void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) {}
-    virtual void endFrame() {}
+    virtual void endFrame(const Rect& repaintRect) {}
 
     // define virtual defaults for single draw methods
 #define X(Type) \
@@ -127,7 +127,7 @@
         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
             EXPECT_EQ(2, mIndex++);
         }
-        void endFrame() override {
+        void endFrame(const Rect& repaintRect) override {
             EXPECT_EQ(3, mIndex++);
         }
     };
@@ -327,7 +327,7 @@
     public:
         void onTextureLayerOp(const TextureLayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(0, mIndex++);
-            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect);
+            EXPECT_EQ(Rect(50, 50, 150, 150), state.computedState.clipRect());
             EXPECT_EQ(Rect(50, 50, 105, 105), state.computedState.clippedBounds);
 
             Matrix4 expected;
@@ -405,7 +405,7 @@
         void onBitmapOp(const BitmapOp& op, const BakedOpState& state) override {
             EXPECT_EQ(0, mIndex++);
             EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect);
+            EXPECT_EQ(Rect(10, 20, 30, 40), state.computedState.clipRect());
             EXPECT_TRUE(state.computedState.transform.isIdentity());
         }
     };
@@ -439,7 +439,7 @@
             EXPECT_EQ(1, mIndex++);
             EXPECT_EQ(Rect(10, 10, 190, 190), op.unmappedBounds);
             EXPECT_EQ(Rect(180, 180), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect);
+            EXPECT_EQ(Rect(180, 180), state.computedState.clipRect());
 
             Matrix4 expectedTransform;
             expectedTransform.loadTranslate(-10, -10, 0);
@@ -448,7 +448,7 @@
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(3, mIndex++);
             EXPECT_EQ(Rect(10, 10, 190, 190), state.computedState.clippedBounds);
-            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect);
+            EXPECT_EQ(Rect(200, 200), state.computedState.clipRect());
             EXPECT_TRUE(state.computedState.transform.isIdentity());
         }
     };
@@ -494,7 +494,7 @@
         void startFrame(uint32_t width, uint32_t height, const Rect& repaintRect) override {
             EXPECT_EQ(7, mIndex++);
         }
-        void endFrame() override {
+        void endFrame(const Rect& repaintRect) override {
             EXPECT_EQ(9, mIndex++);
         }
         void onRectOp(const RectOp& op, const BakedOpState& state) override {
@@ -574,7 +574,7 @@
             EXPECT_TRUE(state.computedState.transform.isIdentity())
                     << "Transform should be reset within layer";
 
-            EXPECT_EQ(state.computedState.clipRect, Rect(25, 25, 75, 75))
+            EXPECT_EQ(Rect(25, 25, 75, 75), state.computedState.clipRect())
                     << "Damage rect should be used to clip layer content";
         }
         void endLayer() override {
@@ -586,7 +586,7 @@
         void onLayerOp(const LayerOp& op, const BakedOpState& state) override {
             EXPECT_EQ(4, mIndex++);
         }
-        void endFrame() override {
+        void endFrame(const Rect& repaintRect) override {
             EXPECT_EQ(5, mIndex++);
         }
     };
@@ -675,7 +675,7 @@
                 EXPECT_EQ(200u, layer->viewportHeight);
             } else { ADD_FAILURE(); }
         }
-        void endFrame() override {
+        void endFrame(const Rect& repaintRect) override {
             EXPECT_EQ(12, mIndex++);
         }
     };
diff --git a/libs/hwui/tests/unit/RecordingCanvasTests.cpp b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
index 08f927c..a63cb18 100644
--- a/libs/hwui/tests/unit/RecordingCanvasTests.cpp
+++ b/libs/hwui/tests/unit/RecordingCanvasTests.cpp
@@ -33,6 +33,14 @@
     }
 }
 
+#define EXPECT_CLIP_RECT(expRect, clipStatePtr) \
+    EXPECT_NE(nullptr, (clipStatePtr)) << "Op is unclipped"; \
+    if ((clipStatePtr)->mode == ClipMode::Rectangle) { \
+        EXPECT_EQ((expRect), reinterpret_cast<const ClipRect*>(clipStatePtr)->rect); \
+    } else { \
+        ADD_FAILURE() << "ClipState not a rect"; \
+    }
+
 TEST(RecordingCanvas, emptyPlayback) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         canvas.save(SkCanvas::kMatrix_SaveFlag | SkCanvas::kClip_SaveFlag);
@@ -41,6 +49,22 @@
     playbackOps(*dl, [](const RecordedOp& op) { ADD_FAILURE(); });
 }
 
+TEST(RecordingCanvas, clipRect) {
+    auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 100, [](RecordingCanvas& canvas) {
+        canvas.save(SkCanvas::kMatrixClip_SaveFlag);
+        canvas.clipRect(0, 0, 100, 100, SkRegion::kIntersect_Op);
+        canvas.drawRect(0, 0, 50, 50, SkPaint());
+        canvas.drawRect(50, 50, 100, 100, SkPaint());
+        canvas.restore();
+    });
+
+    ASSERT_EQ(2u, dl->getOps().size()) << "Must be exactly two ops";
+    EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[0]->localClip);
+    EXPECT_CLIP_RECT(Rect(100, 100), dl->getOps()[1]->localClip);
+    EXPECT_EQ(dl->getOps()[0]->localClip, dl->getOps()[1]->localClip)
+            << "Clip should be serialized once";
+}
+
 TEST(RecordingCanvas, drawLines) {
     auto dl = TestUtils::createDisplayList<RecordingCanvas>(100, 200, [](RecordingCanvas& canvas) {
         SkPaint paint;
@@ -66,7 +90,7 @@
     ASSERT_EQ(1u, dl->getOps().size()) << "Must be exactly one op";
     auto op = *(dl->getOps()[0]);
     ASSERT_EQ(RecordedOpId::RectOp, op.opId);
-    EXPECT_EQ(Rect(100, 200), op.localClipRect);
+    EXPECT_EQ(nullptr, op.localClip);
     EXPECT_EQ(Rect(10, 20, 90, 180), op.unmappedBounds);
 }
 
@@ -83,7 +107,7 @@
     playbackOps(*dl, [&count](const RecordedOp& op) {
         count++;
         ASSERT_EQ(RecordedOpId::TextOp, op.opId);
-        EXPECT_EQ(Rect(200, 200), op.localClipRect);
+        EXPECT_EQ(nullptr, op.localClip);
         EXPECT_TRUE(op.localMatrix.isIdentity());
         EXPECT_TRUE(op.unmappedBounds.contains(25, 15, 50, 25))
                 << "Op expected to be 25+ pixels wide, 10+ pixels tall";
@@ -185,7 +209,7 @@
             ASSERT_NE(nullptr, op.paint);
             EXPECT_EQ(SK_ColorBLUE, op.paint->getColor());
             EXPECT_EQ(Rect(100, 200), op.unmappedBounds);
-            EXPECT_EQ(Rect(100, 200), op.localClipRect);
+            EXPECT_EQ(nullptr, op.localClip);
 
             Matrix4 expectedMatrix;
             expectedMatrix.loadIdentity();
@@ -194,7 +218,7 @@
             ASSERT_EQ(RecordedOpId::BitmapOp, op.opId);
             EXPECT_EQ(nullptr, op.paint);
             EXPECT_EQ(Rect(25, 25), op.unmappedBounds);
-            EXPECT_EQ(Rect(100, 200), op.localClipRect);
+            EXPECT_EQ(nullptr, op.localClip);
 
             Matrix4 expectedMatrix;
             expectedMatrix.loadTranslate(25, 25, 0);
@@ -219,12 +243,12 @@
         case 0:
             EXPECT_EQ(RecordedOpId::BeginLayerOp, op.opId);
             EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
-            EXPECT_EQ(Rect(200, 200), op.localClipRect);
+            EXPECT_EQ(nullptr, op.localClip);
             EXPECT_TRUE(op.localMatrix.isIdentity());
             break;
         case 1:
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(180, 160), op.localClipRect);
+            EXPECT_CLIP_RECT(Rect(180, 160), op.localClip);
             EXPECT_EQ(Rect(10, 20, 190, 180), op.unmappedBounds);
             expectedMatrix.loadTranslate(-10, -20, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -254,8 +278,8 @@
         if (count++ == 1) {
             Matrix4 expectedMatrix;
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(100, 100), op.localClipRect) << "Recorded clip rect should be"
-                    " intersection of viewport and saveLayer bounds, in layer space";
+            EXPECT_CLIP_RECT(Rect(100, 100), op.localClip) // Recorded clip rect should be
+            // intersection of viewport and saveLayer bounds, in layer space;
             EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadTranslate(-100, -100, 0);
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
@@ -281,7 +305,7 @@
     playbackOps(*dl, [&count](const RecordedOp& op) {
         if (count++ == 1) {
             EXPECT_EQ(RecordedOpId::RectOp, op.opId);
-            EXPECT_EQ(Rect(100, 100), op.localClipRect);
+            EXPECT_CLIP_RECT(Rect(100, 100), op.localClip);
             EXPECT_EQ(Rect(100, 100), op.unmappedBounds);
             EXPECT_MATRIX_APPROX_EQ(Matrix4::identity(), op.localMatrix)
                     << "Recorded op shouldn't see any canvas transform before the saveLayer";
@@ -312,7 +336,16 @@
 
             // ...and get about 58.6, 58.6, 341.4 341.4, because the bounds are clipped by
             // the parent 200x200 viewport, but prior to rotation
-            EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136), op.localClipRect);
+            ASSERT_NE(nullptr, op.localClip);
+            ASSERT_EQ(ClipMode::Rectangle, op.localClip->mode);
+            // NOTE: this check relies on saveLayer altering the clip post-viewport init. This
+            // causes the clip to be recorded by contained draw commands, though it's not necessary
+            // since the same clip will be computed at draw time. If such a change is made, this
+            // check could be done at record time by querying the clip, or the clip could be altered
+            // slightly so that it is serialized.
+            EXPECT_RECT_APPROX_EQ(Rect(58.57864, 58.57864, 341.42136, 341.42136),
+                    (reinterpret_cast<const ClipRect*>(op.localClip))->rect);
+
             EXPECT_EQ(Rect(400, 400), op.unmappedBounds);
             expectedMatrix.loadIdentity();
             EXPECT_MATRIX_APPROX_EQ(expectedMatrix, op.localMatrix);
diff --git a/libs/hwui/utils/LinearAllocator.h b/libs/hwui/utils/LinearAllocator.h
index e1c6f6c..dcbc0dd 100644
--- a/libs/hwui/utils/LinearAllocator.h
+++ b/libs/hwui/utils/LinearAllocator.h
@@ -56,12 +56,12 @@
     void* alloc(size_t size);
 
     /**
-     * Allocates an instance of the template type with the default constructor
+     * Allocates an instance of the template type with the given construction parameters
      * and adds it to the automatic destruction list.
      */
-    template<class T>
-    T* alloc() {
-        T* ret = new (*this) T;
+    template<class T, typename... Params>
+    T* create(Params... params) {
+        T* ret = new (*this) T(params...);
         autoDestroy(ret);
         return ret;
     }
diff --git a/media/java/android/media/MediaInserter.java b/media/java/android/media/MediaInserter.java
index 41b369d..dd06921 100644
--- a/media/java/android/media/MediaInserter.java
+++ b/media/java/android/media/MediaInserter.java
@@ -16,8 +16,8 @@
 
 package android.media;
 
+import android.content.ContentProviderClient;
 import android.content.ContentValues;
-import android.content.IContentProvider;
 import android.net.Uri;
 import android.os.RemoteException;
 
@@ -37,13 +37,11 @@
     private final HashMap<Uri, List<ContentValues>> mPriorityRowMap =
             new HashMap<Uri, List<ContentValues>>();
 
-    private final IContentProvider mProvider;
-    private final String mPackageName;
+    private final ContentProviderClient mProvider;
     private final int mBufferSizePerUri;
 
-    public MediaInserter(IContentProvider provider, String packageName, int bufferSizePerUri) {
+    public MediaInserter(ContentProviderClient provider, int bufferSizePerUri) {
         mProvider = provider;
-        mPackageName = packageName;
         mBufferSizePerUri = bufferSizePerUri;
     }
 
@@ -90,7 +88,7 @@
         if (!list.isEmpty()) {
             ContentValues[] valuesArray = new ContentValues[list.size()];
             valuesArray = list.toArray(valuesArray);
-            mProvider.bulkInsert(mPackageName, tableUri, valuesArray);
+            mProvider.bulkInsert(tableUri, valuesArray);
             list.clear();
         }
     }
diff --git a/media/java/android/media/MediaScanner.java b/media/java/android/media/MediaScanner.java
index 9ea6722..96c616b 100644
--- a/media/java/android/media/MediaScanner.java
+++ b/media/java/android/media/MediaScanner.java
@@ -16,14 +16,10 @@
 
 package android.media;
 
-import org.xml.sax.Attributes;
-import org.xml.sax.ContentHandler;
-import org.xml.sax.SAXException;
-
+import android.content.ContentProviderClient;
 import android.content.ContentUris;
 import android.content.ContentValues;
 import android.content.Context;
-import android.content.IContentProvider;
 import android.database.Cursor;
 import android.database.SQLException;
 import android.drm.DrmManagerClient;
@@ -50,6 +46,12 @@
 import android.util.Log;
 import android.util.Xml;
 
+import dalvik.system.CloseGuard;
+
+import org.xml.sax.Attributes;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
+
 import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileDescriptor;
@@ -61,6 +63,7 @@
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * Internal service helper that no-one should use directly.
@@ -107,8 +110,7 @@
  *
  * {@hide}
  */
-public class MediaScanner
-{
+public class MediaScanner implements AutoCloseable {
     static {
         System.loadLibrary("media_jni");
         native_init();
@@ -302,21 +304,23 @@
     };
 
     private long mNativeContext;
-    private Context mContext;
-    private String mPackageName;
-    private IContentProvider mMediaProvider;
-    private Uri mAudioUri;
-    private Uri mVideoUri;
-    private Uri mImagesUri;
-    private Uri mThumbsUri;
-    private Uri mPlaylistsUri;
-    private Uri mFilesUri;
-    private Uri mFilesUriNoNotify;
-    private boolean mProcessPlaylists, mProcessGenres;
+    private final Context mContext;
+    private final String mPackageName;
+    private final String mVolumeName;
+    private final ContentProviderClient mMediaProvider;
+    private final Uri mAudioUri;
+    private final Uri mVideoUri;
+    private final Uri mImagesUri;
+    private final Uri mThumbsUri;
+    private final Uri mPlaylistsUri;
+    private final Uri mFilesUri;
+    private final Uri mFilesUriNoNotify;
+    private final boolean mProcessPlaylists;
+    private final boolean mProcessGenres;
     private int mMtpObjectHandle;
 
-    private final String mExternalStoragePath;
-    private final boolean mExternalIsEmulated;
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
 
     /** whether to use bulk inserts or individual inserts for each item */
     private static final boolean ENABLE_BULK_INSERTS = true;
@@ -345,10 +349,6 @@
      */
     private static final String DEFAULT_RINGTONE_PROPERTY_PREFIX = "ro.config.";
 
-    // set to true if file path comparisons should be case insensitive.
-    // this should be set when scanning files on a case insensitive file system.
-    private boolean mCaseInsensitivePaths;
-
     private final BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options();
 
     private static class FileEntry {
@@ -378,26 +378,59 @@
         int bestmatchlevel;
     }
 
-    private ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<PlaylistEntry>();
+    private final ArrayList<PlaylistEntry> mPlaylistEntries = new ArrayList<>();
+    private final ArrayList<FileEntry> mPlayLists = new ArrayList<>();
 
     private MediaInserter mMediaInserter;
 
-    private ArrayList<FileEntry> mPlayLists;
-
     private DrmManagerClient mDrmManagerClient = null;
 
-    public MediaScanner(Context c) {
+    public MediaScanner(Context c, String volumeName) {
         native_setup();
         mContext = c;
         mPackageName = c.getPackageName();
+        mVolumeName = volumeName;
+
         mBitmapOptions.inSampleSize = 1;
         mBitmapOptions.inJustDecodeBounds = true;
 
         setDefaultRingtoneFileNames();
 
-        mExternalStoragePath = Environment.getExternalStorageDirectory().getAbsolutePath();
-        mExternalIsEmulated = Environment.isExternalStorageEmulated();
-        //mClient.testGenreNameConverter();
+        mMediaProvider = mContext.getContentResolver()
+                .acquireContentProviderClient(MediaStore.AUTHORITY);
+
+        mAudioUri = Audio.Media.getContentUri(volumeName);
+        mVideoUri = Video.Media.getContentUri(volumeName);
+        mImagesUri = Images.Media.getContentUri(volumeName);
+        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
+        mFilesUri = Files.getContentUri(volumeName);
+        mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
+
+        if (!volumeName.equals("internal")) {
+            // we only support playlists on external media
+            mProcessPlaylists = true;
+            mProcessGenres = true;
+            mPlaylistsUri = Playlists.getContentUri(volumeName);
+        } else {
+            mProcessPlaylists = false;
+            mProcessGenres = false;
+            mPlaylistsUri = null;
+        }
+
+        final Locale locale = mContext.getResources().getConfiguration().locale;
+        if (locale != null) {
+            String language = locale.getLanguage();
+            String country = locale.getCountry();
+            if (language != null) {
+                if (country != null) {
+                    setLocale(language + "_" + country);
+                } else {
+                    setLocale(language);
+                }
+            }
+        }
+
+        mCloseGuard.open("close");
     }
 
     private void setDefaultRingtoneFileNames() {
@@ -956,7 +989,7 @@
                     if (inserter != null) {
                         inserter.flushAll();
                     }
-                    result = mMediaProvider.insert(mPackageName, tableUri, values);
+                    result = mMediaProvider.insert(tableUri, values);
                 } else if (entry.mFormat == MtpConstants.FORMAT_ASSOCIATION) {
                     inserter.insertwithPriority(tableUri, values);
                 } else {
@@ -988,7 +1021,7 @@
                     }
                     values.put(FileColumns.MEDIA_TYPE, mediaType);
                 }
-                mMediaProvider.update(mPackageName, result, values, null, null);
+                mMediaProvider.update(result, values, null, null);
             }
 
             if(needToSetSettings) {
@@ -1055,11 +1088,7 @@
         String where = null;
         String[] selectionArgs = null;
 
-        if (mPlayLists == null) {
-            mPlayLists = new ArrayList<FileEntry>();
-        } else {
-            mPlayLists.clear();
-        }
+        mPlayLists.clear();
 
         if (filePath != null) {
             // query for only one file
@@ -1077,8 +1106,7 @@
         // filesystem is mounted and unmounted while the scanner is running).
         Uri.Builder builder = mFilesUri.buildUpon();
         builder.appendQueryParameter(MediaStore.PARAM_DELETE_DATA, "false");
-        MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, mPackageName,
-                builder.build());
+        MediaBulkDeleter deleter = new MediaBulkDeleter(mMediaProvider, builder.build());
 
         // Build the list of files from the content provider
         try {
@@ -1097,7 +1125,7 @@
                         c.close();
                         c = null;
                     }
-                    c = mMediaProvider.query(mPackageName, limitUri, FILES_PRESCAN_PROJECTION,
+                    c = mMediaProvider.query(limitUri, FILES_PRESCAN_PROJECTION,
                             where, selectionArgs, MediaStore.Files.FileColumns._ID, null);
                     if (c == null) {
                         break;
@@ -1138,8 +1166,7 @@
                                     if (path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
                                         deleter.flush();
                                         String parent = new File(path).getParent();
-                                        mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL,
-                                                parent, null);
+                                        mMediaProvider.call(MediaStore.UNHIDE_CALL, parent, null);
                                     }
                                 }
                             }
@@ -1157,7 +1184,7 @@
 
         // compute original size of images
         mOriginalCount = 0;
-        c = mMediaProvider.query(mPackageName, mImagesUri, ID_PROJECTION, null, null, null, null);
+        c = mMediaProvider.query(mImagesUri, ID_PROJECTION, null, null, null, null);
         if (c != null) {
             mOriginalCount = c.getCount();
             c.close();
@@ -1189,7 +1216,6 @@
 
         try {
             c = mMediaProvider.query(
-                    mPackageName,
                     mThumbsUri,
                     new String [] { "_data" },
                     null,
@@ -1225,13 +1251,11 @@
     static class MediaBulkDeleter {
         StringBuilder whereClause = new StringBuilder();
         ArrayList<String> whereArgs = new ArrayList<String>(100);
-        final IContentProvider mProvider;
-        final String mPackageName;
+        final ContentProviderClient mProvider;
         final Uri mBaseUri;
 
-        public MediaBulkDeleter(IContentProvider provider, String packageName, Uri baseUri) {
+        public MediaBulkDeleter(ContentProviderClient provider, Uri baseUri) {
             mProvider = provider;
-            mPackageName = packageName;
             mBaseUri = baseUri;
         }
 
@@ -1250,7 +1274,7 @@
             if (size > 0) {
                 String [] foo = new String [size];
                 foo = whereArgs.toArray(foo);
-                int numrows = mProvider.delete(mPackageName, mBaseUri,
+                int numrows = mProvider.delete(mBaseUri,
                         MediaStore.MediaColumns._ID + " IN (" +
                         whereClause.toString() + ")", foo);
                 //Log.i("@@@@@@@@@", "rows deleted: " + numrows);
@@ -1271,48 +1295,26 @@
             pruneDeadThumbnailFiles();
 
         // allow GC to clean up
-        mPlayLists = null;
-        mMediaProvider = null;
+        mPlayLists.clear();
     }
 
     private void releaseResources() {
         // release the DrmManagerClient resources
         if (mDrmManagerClient != null) {
-            mDrmManagerClient.release();
+            mDrmManagerClient.close();
             mDrmManagerClient = null;
         }
     }
 
-    private void initialize(String volumeName) {
-        mMediaProvider = mContext.getContentResolver().acquireProvider("media");
-
-        mAudioUri = Audio.Media.getContentUri(volumeName);
-        mVideoUri = Video.Media.getContentUri(volumeName);
-        mImagesUri = Images.Media.getContentUri(volumeName);
-        mThumbsUri = Images.Thumbnails.getContentUri(volumeName);
-        mFilesUri = Files.getContentUri(volumeName);
-        mFilesUriNoNotify = mFilesUri.buildUpon().appendQueryParameter("nonotify", "1").build();
-
-        if (!volumeName.equals("internal")) {
-            // we only support playlists on external media
-            mProcessPlaylists = true;
-            mProcessGenres = true;
-            mPlaylistsUri = Playlists.getContentUri(volumeName);
-
-            mCaseInsensitivePaths = true;
-        }
-    }
-
-    public void scanDirectories(String[] directories, String volumeName) {
+    public void scanDirectories(String[] directories) {
         try {
             long start = System.currentTimeMillis();
-            initialize(volumeName);
             prescan(null, true);
             long prescan = System.currentTimeMillis();
 
             if (ENABLE_BULK_INSERTS) {
                 // create MediaInserter for bulk inserts
-                mMediaInserter = new MediaInserter(mMediaProvider, mPackageName, 500);
+                mMediaInserter = new MediaInserter(mMediaProvider, 500);
             }
 
             for (int i = 0; i < directories.length; i++) {
@@ -1349,9 +1351,8 @@
     }
 
     // this function is used to scan a single file
-    public Uri scanSingleFile(String path, String volumeName, String mimeType) {
+    public Uri scanSingleFile(String path, String mimeType) {
         try {
-            initialize(volumeName);
             prescan(path, true);
 
             File file = new File(path);
@@ -1464,8 +1465,7 @@
         return isNoMediaFile(path);
     }
 
-    public void scanMtpFile(String path, String volumeName, int objectHandle, int format) {
-        initialize(volumeName);
+    public void scanMtpFile(String path, int objectHandle, int format) {
         MediaFile.MediaFileType mediaFileType = MediaFile.getFileType(path);
         int fileType = (mediaFileType == null ? 0 : mediaFileType.fileType);
         File file = new File(path);
@@ -1481,7 +1481,7 @@
             values.put(Files.FileColumns.DATE_MODIFIED, lastModifiedSeconds);
             try {
                 String[] whereArgs = new String[] {  Integer.toString(objectHandle) };
-                mMediaProvider.update(mPackageName, Files.getMtpObjectsUri(volumeName), values,
+                mMediaProvider.update(Files.getMtpObjectsUri(mVolumeName), values,
                         "_id=?", whereArgs);
             } catch (RemoteException e) {
                 Log.e(TAG, "RemoteException in scanMtpFile", e);
@@ -1498,7 +1498,7 @@
 
                 FileEntry entry = makeEntryFor(path);
                 if (entry != null) {
-                    fileList = mMediaProvider.query(mPackageName, mFilesUri,
+                    fileList = mMediaProvider.query(mFilesUri,
                             FILES_PRESCAN_PROJECTION, null, null, null, null);
                     processPlayList(entry, fileList);
                 }
@@ -1529,7 +1529,7 @@
         try {
             where = Files.FileColumns.DATA + "=?";
             selectionArgs = new String[] { path };
-            c = mMediaProvider.query(mPackageName, mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
+            c = mMediaProvider.query(mFilesUriNoNotify, FILES_PRESCAN_PROJECTION,
                     where, selectionArgs, null, null);
             if (c.moveToFirst()) {
                 long rowId = c.getLong(FILES_PRESCAN_ID_COLUMN_INDEX);
@@ -1641,7 +1641,7 @@
                     values.clear();
                     values.put(MediaStore.Audio.Playlists.Members.PLAY_ORDER, Integer.valueOf(index));
                     values.put(MediaStore.Audio.Playlists.Members.AUDIO_ID, Long.valueOf(entry.bestmatchid));
-                    mMediaProvider.insert(mPackageName, playlistUri, values);
+                    mMediaProvider.insert(playlistUri, values);
                     index++;
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException in MediaScanner.processCachedPlaylist()", e);
@@ -1806,16 +1806,16 @@
 
         if (rowId == 0) {
             values.put(MediaStore.Audio.Playlists.DATA, path);
-            uri = mMediaProvider.insert(mPackageName, mPlaylistsUri, values);
+            uri = mMediaProvider.insert(mPlaylistsUri, values);
             rowId = ContentUris.parseId(uri);
             membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
         } else {
             uri = ContentUris.withAppendedId(mPlaylistsUri, rowId);
-            mMediaProvider.update(mPackageName, uri, values, null, null);
+            mMediaProvider.update(uri, values, null, null);
 
             // delete members of existing playlist
             membersUri = Uri.withAppendedPath(uri, Playlists.Members.CONTENT_DIRECTORY);
-            mMediaProvider.delete(mPackageName, membersUri, null, null);
+            mMediaProvider.delete(membersUri, null, null);
         }
 
         String playListDirectory = path.substring(0, lastSlash + 1);
@@ -1837,7 +1837,7 @@
         try {
             // use the files uri and projection because we need the format column,
             // but restrict the query to just audio files
-            fileList = mMediaProvider.query(mPackageName, mFilesUri, FILES_PRESCAN_PROJECTION,
+            fileList = mMediaProvider.query(mFilesUri, FILES_PRESCAN_PROJECTION,
                     "media_type=2", null, null, null);
             while (iterator.hasNext()) {
                 FileEntry entry = iterator.next();
@@ -1856,7 +1856,7 @@
 
     private native void processDirectory(String path, MediaScannerClient client);
     private native void processFile(String path, String mimeType, MediaScannerClient client);
-    public native void setLocale(String locale);
+    private native void setLocale(String locale);
 
     public native byte[] extractAlbumArt(FileDescriptor fd);
 
@@ -1864,19 +1864,22 @@
     private native final void native_setup();
     private native final void native_finalize();
 
-    /**
-     * Releases resources associated with this MediaScanner object.
-     * It is considered good practice to call this method when
-     * one is done using the MediaScanner object. After this method
-     * is called, the MediaScanner object can no longer be used.
-     */
-    public void release() {
-        native_finalize();
+    @Override
+    public void close() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            mMediaProvider.close();
+            native_finalize();
+        }
     }
 
     @Override
-    protected void finalize() {
-        mContext.getContentResolver().releaseProvider(mMediaProvider);
-        native_finalize();
+    protected void finalize() throws Throwable {
+        try {
+            mCloseGuard.warnIfOpen();
+            close();
+        } finally {
+            super.finalize();
+        }
     }
 }
diff --git a/media/java/android/mtp/MtpDatabase.java b/media/java/android/mtp/MtpDatabase.java
index 3541fba..bc96e2e 100755
--- a/media/java/android/mtp/MtpDatabase.java
+++ b/media/java/android/mtp/MtpDatabase.java
@@ -17,9 +17,9 @@
 package android.mtp;
 
 import android.content.BroadcastReceiver;
-import android.content.Context;
+import android.content.ContentProviderClient;
 import android.content.ContentValues;
-import android.content.IContentProvider;
+import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.SharedPreferences;
@@ -37,23 +37,30 @@
 import android.view.Display;
 import android.view.WindowManager;
 
+import dalvik.system.CloseGuard;
+
 import java.io.File;
 import java.io.IOException;
 import java.util.HashMap;
 import java.util.Locale;
+import java.util.concurrent.atomic.AtomicBoolean;
 
 /**
  * {@hide}
  */
-public class MtpDatabase {
-
+public class MtpDatabase implements AutoCloseable {
     private static final String TAG = "MtpDatabase";
 
     private final Context mContext;
     private final String mPackageName;
-    private final IContentProvider mMediaProvider;
+    private final ContentProviderClient mMediaProvider;
     private final String mVolumeName;
     private final Uri mObjectsUri;
+    private final MediaScanner mMediaScanner;
+
+    private final AtomicBoolean mClosed = new AtomicBoolean();
+    private final CloseGuard mCloseGuard = CloseGuard.get();
+
     // path to primary storage
     private final String mMediaStoragePath;
     // if not null, restrict all queries to these subdirectories
@@ -120,7 +127,6 @@
     private static final String STORAGE_FORMAT_PARENT_WHERE = STORAGE_FORMAT_WHERE + " AND "
                                             + Files.FileColumns.PARENT + "=?";
 
-    private final MediaScanner mMediaScanner;
     private MtpServer mServer;
 
     // read from native code
@@ -156,11 +162,12 @@
 
         mContext = context;
         mPackageName = context.getPackageName();
-        mMediaProvider = context.getContentResolver().acquireProvider("media");
+        mMediaProvider = context.getContentResolver()
+                .acquireContentProviderClient(MediaStore.AUTHORITY);
         mVolumeName = volumeName;
         mMediaStoragePath = storagePath;
         mObjectsUri = Files.getMtpObjectsUri(volumeName);
-        mMediaScanner = new MediaScanner(context);
+        mMediaScanner = new MediaScanner(context, mVolumeName);
 
         mSubDirectories = subDirectories;
         if (subDirectories != null) {
@@ -187,20 +194,9 @@
             }
         }
 
-        // Set locale to MediaScanner.
-        Locale locale = context.getResources().getConfiguration().locale;
-        if (locale != null) {
-            String language = locale.getLanguage();
-            String country = locale.getCountry();
-            if (language != null) {
-                if (country != null) {
-                    mMediaScanner.setLocale(language + "_" + country);
-                } else {
-                    mMediaScanner.setLocale(language);
-                }
-            }
-        }
         initDeviceProperties(context);
+
+        mCloseGuard.open("close");
     }
 
     public void setServer(MtpServer server) {
@@ -221,9 +217,20 @@
     }
 
     @Override
+    public void close() {
+        mCloseGuard.close();
+        if (mClosed.compareAndSet(false, true)) {
+            mMediaScanner.close();
+            mMediaProvider.close();
+            native_finalize();
+        }
+    }
+
+    @Override
     protected void finalize() throws Throwable {
         try {
-            native_finalize();
+            mCloseGuard.warnIfOpen();
+            close();
         } finally {
             super.finalize();
         }
@@ -334,7 +341,7 @@
         if (path != null) {
             Cursor c = null;
             try {
-                c = mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, PATH_WHERE,
+                c = mMediaProvider.query(mObjectsUri, ID_PROJECTION, PATH_WHERE,
                         new String[] { path }, null, null);
                 if (c != null && c.getCount() > 0) {
                     Log.w(TAG, "file already exists in beginSendObject: " + path);
@@ -359,7 +366,7 @@
         values.put(Files.FileColumns.DATE_MODIFIED, modified);
 
         try {
-            Uri uri = mMediaProvider.insert(mPackageName, mObjectsUri, values);
+            Uri uri = mMediaProvider.insert(mObjectsUri, values);
             if (uri != null) {
                 return Integer.parseInt(uri.getPathSegments().get(2));
             } else {
@@ -394,13 +401,13 @@
                 values.put(Files.FileColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
                 values.put(MediaColumns.MEDIA_SCANNER_NEW_OBJECT_ID, handle);
                 try {
-                    Uri uri = mMediaProvider.insert(mPackageName,
+                    Uri uri = mMediaProvider.insert(
                             Audio.Playlists.EXTERNAL_CONTENT_URI, values);
                 } catch (RemoteException e) {
                     Log.e(TAG, "RemoteException in endSendObject", e);
                 }
             } else {
-                mMediaScanner.scanMtpFile(path, mVolumeName, handle, format);
+                mMediaScanner.scanMtpFile(path, handle, format);
             }
         } else {
             deleteFile(handle);
@@ -503,7 +510,7 @@
             }
         }
 
-        return mMediaProvider.query(mPackageName, mObjectsUri, ID_PROJECTION, where,
+        return mMediaProvider.query(mObjectsUri, ID_PROJECTION, where,
                 whereArgs, null, null);
     }
 
@@ -721,7 +728,7 @@
              propertyGroup = mPropertyGroupsByFormat.get(format);
              if (propertyGroup == null) {
                 int[] propertyList = getSupportedObjectProperties(format);
-                propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+                propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
                         mVolumeName, propertyList);
                 mPropertyGroupsByFormat.put(new Integer(format), propertyGroup);
             }
@@ -729,7 +736,7 @@
               propertyGroup = mPropertyGroupsByProperty.get(property);
              if (propertyGroup == null) {
                 int[] propertyList = new int[] { (int)property };
-                propertyGroup = new MtpPropertyGroup(this, mMediaProvider, mPackageName,
+                propertyGroup = new MtpPropertyGroup(this, mMediaProvider,
                         mVolumeName, propertyList);
                 mPropertyGroupsByProperty.put(new Integer((int)property), propertyGroup);
             }
@@ -745,7 +752,7 @@
         String path = null;
         String[] whereArgs = new String[] {  Integer.toString(handle) };
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_PROJECTION, ID_WHERE,
+            c = mMediaProvider.query(mObjectsUri, PATH_PROJECTION, ID_WHERE,
                     whereArgs, null, null);
             if (c != null && c.moveToNext()) {
                 path = c.getString(1);
@@ -788,7 +795,7 @@
         try {
             // note - we are relying on a special case in MediaProvider.update() to update
             // the paths for all children in the case where this is a directory.
-            updated = mMediaProvider.update(mPackageName, mObjectsUri, values, ID_WHERE, whereArgs);
+            updated = mMediaProvider.update(mObjectsUri, values, ID_WHERE, whereArgs);
         } catch (RemoteException e) {
             Log.e(TAG, "RemoteException in mMediaProvider.update", e);
         }
@@ -805,7 +812,7 @@
             if (oldFile.getName().startsWith(".") && !newPath.startsWith(".")) {
                 // directory was unhidden
                 try {
-                    mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, newPath, null);
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, newPath, null);
                 } catch (RemoteException e) {
                     Log.e(TAG, "failed to unhide/rescan for " + newPath);
                 }
@@ -815,7 +822,7 @@
             if (oldFile.getName().toLowerCase(Locale.US).equals(".nomedia")
                     && !newPath.toLowerCase(Locale.US).equals(".nomedia")) {
                 try {
-                    mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
+                    mMediaProvider.call(MediaStore.UNHIDE_CALL, oldFile.getParent(), null);
                 } catch (RemoteException e) {
                     Log.e(TAG, "failed to unhide/rescan for " + newPath);
                 }
@@ -886,7 +893,7 @@
                         char[] outName, long[] outCreatedModified) {
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, OBJECT_INFO_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, OBJECT_INFO_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 outStorageFormatParent[0] = c.getInt(1);
@@ -933,7 +940,7 @@
         }
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 String path = c.getString(1);
@@ -960,7 +967,7 @@
     private int getObjectFormat(int handle) {
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, FORMAT_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, FORMAT_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 return c.getInt(1);
@@ -984,7 +991,7 @@
 
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, mObjectsUri, PATH_FORMAT_PROJECTION,
+            c = mMediaProvider.query(mObjectsUri, PATH_FORMAT_PROJECTION,
                             ID_WHERE, new String[] {  Integer.toString(handle) }, null, null);
             if (c != null && c.moveToNext()) {
                 // don't convert to media path here, since we will be matching
@@ -1007,7 +1014,7 @@
             if (format == MtpConstants.FORMAT_ASSOCIATION) {
                 // recursive case - delete all children first
                 Uri uri = Files.getMtpObjectsUri(mVolumeName);
-                int count = mMediaProvider.delete(mPackageName, uri,
+                int count = mMediaProvider.delete(uri,
                     // the 'like' makes it use the index, the 'lower()' makes it correct
                     // when the path contains sqlite wildcard characters
                     "_data LIKE ?1 AND lower(substr(_data,1,?2))=lower(?3)",
@@ -1015,12 +1022,12 @@
             }
 
             Uri uri = Files.getMtpObjectsUri(mVolumeName, handle);
-            if (mMediaProvider.delete(mPackageName, uri, null, null) > 0) {
+            if (mMediaProvider.delete(uri, null, null) > 0) {
                 if (format != MtpConstants.FORMAT_ASSOCIATION
                         && path.toLowerCase(Locale.US).endsWith("/.nomedia")) {
                     try {
                         String parentPath = path.substring(0, path.lastIndexOf("/"));
-                        mMediaProvider.call(mPackageName, MediaStore.UNHIDE_CALL, parentPath, null);
+                        mMediaProvider.call(MediaStore.UNHIDE_CALL, parentPath, null);
                     } catch (RemoteException e) {
                         Log.e(TAG, "failed to unhide/rescan for " + path);
                     }
@@ -1043,7 +1050,7 @@
         Uri uri = Files.getMtpReferencesUri(mVolumeName, handle);
         Cursor c = null;
         try {
-            c = mMediaProvider.query(mPackageName, uri, ID_PROJECTION, null, null, null, null);
+            c = mMediaProvider.query(uri, ID_PROJECTION, null, null, null, null);
             if (c == null) {
                 return null;
             }
@@ -1077,7 +1084,7 @@
             valuesList[i] = values;
         }
         try {
-            if (mMediaProvider.bulkInsert(mPackageName, uri, valuesList) > 0) {
+            if (mMediaProvider.bulkInsert(uri, valuesList) > 0) {
                 return MtpConstants.RESPONSE_OK;
             }
         } catch (RemoteException e) {
diff --git a/media/java/android/mtp/MtpPropertyGroup.java b/media/java/android/mtp/MtpPropertyGroup.java
index c80adfa..dea3008 100644
--- a/media/java/android/mtp/MtpPropertyGroup.java
+++ b/media/java/android/mtp/MtpPropertyGroup.java
@@ -16,7 +16,7 @@
 
 package android.mtp;
 
-import android.content.IContentProvider;
+import android.content.ContentProviderClient;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.RemoteException;
@@ -48,8 +48,7 @@
     }
 
     private final MtpDatabase mDatabase;
-    private final IContentProvider mProvider;
-    private final String mPackageName;
+    private final ContentProviderClient mProvider;
     private final String mVolumeName;
     private final Uri mUri;
 
@@ -65,13 +64,12 @@
     private static final String PARENT_WHERE = Files.FileColumns.PARENT + "=?";
     private static final String PARENT_FORMAT_WHERE = PARENT_WHERE + " AND " + FORMAT_WHERE;
     // constructs a property group for a list of properties
-    public MtpPropertyGroup(MtpDatabase database, IContentProvider provider, String packageName,
-            String volume, int[] properties) {
+    public MtpPropertyGroup(MtpDatabase database, ContentProviderClient provider, String volumeName,
+            int[] properties) {
         mDatabase = database;
         mProvider = provider;
-        mPackageName = packageName;
-        mVolumeName = volume;
-        mUri = Files.getMtpObjectsUri(volume);
+        mVolumeName = volumeName;
+        mUri = Files.getMtpObjectsUri(volumeName);
 
         int count = properties.length;
         ArrayList<String> columns = new ArrayList<String>(count);
@@ -201,7 +199,7 @@
         Cursor c = null;
         try {
             // for now we are only reading properties from the "objects" table
-            c = mProvider.query(mPackageName, mUri,
+            c = mProvider.query(mUri,
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
@@ -221,7 +219,7 @@
     private String queryAudio(int id, String column) {
         Cursor c = null;
         try {
-            c = mProvider.query(mPackageName, Audio.Media.getContentUri(mVolumeName),
+            c = mProvider.query(Audio.Media.getContentUri(mVolumeName),
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
@@ -242,7 +240,7 @@
         Cursor c = null;
         try {
             Uri uri = Audio.Genres.getContentUriForAudioId(mVolumeName, id);
-            c = mProvider.query(mPackageName, uri,
+            c = mProvider.query(uri,
                             new String [] { Files.FileColumns._ID, Audio.GenresColumns.NAME },
                             null, null, null, null);
             if (c != null && c.moveToNext()) {
@@ -264,7 +262,7 @@
         Cursor c = null;
         try {
             // for now we are only reading properties from the "objects" table
-            c = mProvider.query(mPackageName, mUri,
+            c = mProvider.query(mUri,
                             new String [] { Files.FileColumns._ID, column },
                             ID_WHERE, new String[] { Integer.toString(id) }, null, null);
             if (c != null && c.moveToNext()) {
@@ -335,7 +333,7 @@
         try {
             // don't query if not necessary
             if (depth > 0 || handle == 0xFFFFFFFF || mColumns.length > 1) {
-                c = mProvider.query(mPackageName, mUri, mColumns, where, whereArgs, null, null);
+                c = mProvider.query(mUri, mColumns, where, whereArgs, null, null);
                 if (c == null) {
                     return new MtpPropertyList(0, MtpConstants.RESPONSE_INVALID_OBJECT_HANDLE);
                 }
diff --git a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
index 05df014..06efa90 100644
--- a/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
+++ b/media/tests/MediaFrameworkTest/src/com/android/mediaframeworktest/unit/MediaInserterTest.java
@@ -16,6 +16,7 @@
 
 package com.android.mediaframeworktest.unit;
 
+import android.content.ContentProviderClient;
 import android.content.ContentValues;
 import android.content.IContentProvider;
 import android.media.MediaInserter;
@@ -81,8 +82,9 @@
     protected void setUp() throws Exception {
         super.setUp();
         mMockProvider = EasyMock.createMock(IContentProvider.class);
-        mMediaInserter = new MediaInserter(mMockProvider,
-        mPackageName, TEST_BUFFER_SIZE);
+        final ContentProviderClient client = new ContentProviderClient(
+                getInstrumentation().getContext().getContentResolver(), mMockProvider, true);
+        mMediaInserter = new MediaInserter(client, TEST_BUFFER_SIZE);
         mPackageName = getInstrumentation().getContext().getPackageName();
         mFilesCounter = 0;
         mAudioCounter = 0;
diff --git a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 65e42aa..0000000
--- a/packages/DocumentsUI/res/drawable-hdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 1de8292..0000000
--- a/packages/DocumentsUI/res/drawable-mdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 00b8a8b7..0000000
--- a/packages/DocumentsUI/res/drawable-xhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index 5236774..0000000
--- a/packages/DocumentsUI/res/drawable-xxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png b/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
deleted file mode 100644
index c7daa2a..0000000
--- a/packages/DocumentsUI/res/drawable-xxxhdpi/ic_root_sdcard_alpha.png
+++ /dev/null
Binary files differ
diff --git a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml b/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
deleted file mode 100644
index 27cfa81d..0000000
--- a/packages/DocumentsUI/res/drawable/ic_root_sdcard.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
-    android:src="@drawable/ic_root_sdcard_alpha"
-    android:tint="?android:attr/colorControlNormal" />
diff --git a/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
new file mode 100644
index 0000000..3021b16
--- /dev/null
+++ b/packages/DocumentsUI/res/drawable/ic_root_smartphone.xml
@@ -0,0 +1,24 @@
+<!--
+Copyright (C) 2015 The Android Open Source Project
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M17 1.01L7 1c-1.1 0,-2 .9,-2 2v18c0 1.1.9 2 2 2h10c1.1 0 2,-.9 2,-2V3c0,-1.1,-.9,-1.99,-2,-1.99zM17 19H7V5h10v14z"/>
+</vector>
diff --git a/packages/DocumentsUI/res/values-sw/strings.xml b/packages/DocumentsUI/res/values-sw/strings.xml
index b522e0a..c303e0c 100644
--- a/packages/DocumentsUI/res/values-sw/strings.xml
+++ b/packages/DocumentsUI/res/values-sw/strings.xml
@@ -97,8 +97,8 @@
     <string name="copy_failure_alert_content" msgid="3715575000297709082">"Faili hizi hazikunakiliwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <string name="move_failure_alert_content" msgid="7151140279020481180">"Faili hizi hazikuhamishwa: <xliff:g id="LIST">%1$s</xliff:g>"</string>
     <plurals name="clipboard_files_clipped" formatted="false" msgid="855459017537058539">
-      <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubaoklipu.</item>
-      <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubaoklipu.</item>
+      <item quantity="other">Alinakili faili <xliff:g id="COUNT_1">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
+      <item quantity="one">Alinakili faili <xliff:g id="COUNT_0">%1$d</xliff:g> kwenye ubao wa kunakili.</item>
     </plurals>
     <string name="clipboard_files_cannot_paste" msgid="2878324825602325706">"Haiwezi kubandika faili zilizochaguliwa katika eneo hili."</string>
 </resources>
diff --git a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
index 4eacee5..6719b23 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/DirectoryLoader.java
@@ -114,11 +114,7 @@
         if (userMode != State.MODE_UNKNOWN) {
             result.mode = userMode;
         } else {
-            if ((mDoc.flags & Document.FLAG_DIR_PREFERS_GRID) != 0) {
-                result.mode = State.MODE_GRID;
-            } else {
-                result.mode = State.MODE_LIST;
-            }
+            result.mode = State.MODE_GRID;
         }
 
         if (mUserSortOrder != State.SORT_ORDER_UNKNOWN) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/State.java b/packages/DocumentsUI/src/com/android/documentsui/State.java
index c81d4fb..46372c0 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/State.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/State.java
@@ -36,7 +36,7 @@
     /** Explicit user choice */
     public int userMode = MODE_UNKNOWN;
     /** Derived after loader */
-    public int derivedMode = MODE_LIST;
+    public int derivedMode = MODE_GRID;
 
     /** Explicit user choice */
     public int userSortOrder = SORT_ORDER_UNKNOWN;
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
index 0d5e34e..9617582 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DirectoryFragment.java
@@ -53,6 +53,7 @@
 import android.support.annotation.Nullable;
 import android.support.design.widget.Snackbar;
 import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.GridLayoutManager.SpanSizeLookup;
 import android.support.v7.widget.LinearLayoutManager;
 import android.support.v7.widget.RecyclerView;
 import android.support.v7.widget.RecyclerView.LayoutManager;
@@ -99,18 +100,17 @@
 import com.android.documentsui.model.DocumentInfo;
 import com.android.documentsui.model.DocumentStack;
 import com.android.documentsui.model.RootInfo;
+
 import com.google.common.collect.Lists;
-import com.google.common.collect.Sets;
 
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
-import java.util.Set;
 
 /**
  * Display the documents inside a single directory.
  */
-public class DirectoryFragment extends Fragment {
+public class DirectoryFragment extends Fragment implements DocumentsAdapter.Environment {
 
     public static final int TYPE_NORMAL = 1;
     public static final int TYPE_SEARCH = 2;
@@ -126,7 +126,7 @@
     private static final String TAG = "DirectoryFragment";
 
     private static final int LOADER_ID = 42;
-    private static final boolean DEBUG_ENABLE_DND = true;
+    static final boolean DEBUG_ENABLE_DND = true;
 
     private static final String EXTRA_TYPE = "type";
     private static final String EXTRA_ROOT = "root";
@@ -289,7 +289,11 @@
         final RootInfo root = getArguments().getParcelable(EXTRA_ROOT);
         final DocumentInfo doc = getArguments().getParcelable(EXTRA_DOC);
 
-        mAdapter = new DocumentsAdapter();
+        mIconHelper = new IconHelper(context, state.derivedMode);
+
+        mAdapter = new SectionBreakDocumentsAdapterWrapper(
+                this, new ModelBackedDocumentsAdapter(this, mIconHelper));
+
         mRecView.setAdapter(mAdapter);
 
         GestureDetector.SimpleOnGestureListener listener =
@@ -328,12 +332,13 @@
         // into the selection manager.
         mSelectionManager = new MultiSelectManager(
                 mRecView,
+                mAdapter,
                 state.allowMultiple
                     ? MultiSelectManager.MODE_MULTIPLE
                     : MultiSelectManager.MODE_SINGLE);
         mSelectionManager.addCallback(new SelectionModeListener());
 
-        mModel = new Model(context, mAdapter);
+        mModel = new Model(context);
         mModel.addUpdateListener(mAdapter);
         mModel.addUpdateListener(mModelUpdateListener);
 
@@ -343,8 +348,6 @@
         mTuner = FragmentTuner.pick(state);
         mClipper = new DocumentClipper(context);
 
-        mIconHelper = new IconHelper(context, state.derivedMode);
-
         boolean hideGridTitles;
         if (mType == TYPE_RECENT_OPEN) {
             // Hide titles when showing recents for picking images/videos
@@ -574,7 +577,10 @@
             case MODE_GRID:
                 if (mGridLayout == null) {
                     mGridLayout = new GridLayoutManager(getContext(), mColumnCount);
-                    mGridLayout.setSpanSizeLookup(mAdapter.createSpanSizeLookup());
+                    SpanSizeLookup lookup = mAdapter.createSpanSizeLookup();
+                    if (lookup != null) {
+                        mGridLayout.setSpanSizeLookup(lookup);
+                    }
                 }
                 layout = mGridLayout;
                 break;
@@ -609,6 +615,11 @@
         return columnCount;
     }
 
+    @Override
+    public int getColumnCount() {
+        return mColumnCount;
+    }
+
     /**
      * Manages the integration between our ActionMode and MultiSelectManager, initiating
      * ActionMode when there is a selection, canceling it when there is no selection,
@@ -893,10 +904,34 @@
         }.execute(selected);
     }
 
-    private State getDisplayState() {
+    @Override
+    public void initDocumentHolder(DocumentHolder holder) {
+        holder.addClickListener(mItemClickListener);
+        holder.addOnKeyListener(mSelectionManager);
+    }
+
+    @Override
+    public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {
+        if (DEBUG_ENABLE_DND) {
+            setupDragAndDropOnDocumentView(holder.itemView, cursor);
+        }
+    }
+
+    @Override
+    public State getDisplayState() {
         return ((BaseActivity) getActivity()).getDisplayState();
     }
 
+    @Override
+    public Model getModel() {
+        return mModel;
+    }
+
+    @Override
+    public boolean isDocumentEnabled(String docMimeType, int docFlags) {
+        return mTuner.isDocumentEnabled(docMimeType, docFlags);
+    }
+
     void showEmptyView() {
         mEmptyView.setVisibility(View.VISIBLE);
         mRecView.setVisibility(View.GONE);
@@ -920,240 +955,6 @@
         mRecView.setVisibility(View.VISIBLE);
     }
 
-    final class DocumentsAdapter
-            extends RecyclerView.Adapter<DocumentHolder>
-            implements Model.UpdateListener {
-
-        private static final String TAG = "DocumentsAdapter";
-        public static final int ITEM_TYPE_LAYOUT_DIVIDER = 0;
-        public static final int ITEM_TYPE_DOCUMENT = 1;
-        public static final int ITEM_TYPE_DIRECTORY = 2;
-
-        /**
-         * An ordered list of model IDs. This is the data structure that determines what shows up in
-         * the UI, and where.
-         */
-        private List<String> mModelIds = new ArrayList<>();
-
-        // The list is divided into two segments - directories, and everything else. Record the
-        // position where the transition happens.
-        private int mDividerPosition;
-
-        public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
-            return new GridLayoutManager.SpanSizeLookup() {
-                @Override
-                public int getSpanSize(int position) {
-                    // Make layout whitespace span the grid. This has the effect of breaking
-                    // grid rows whenever layout whitespace is encountered.
-                    if (getItemViewType(position) == ITEM_TYPE_LAYOUT_DIVIDER) {
-                        return mColumnCount;
-                    } else {
-                        return 1;
-                    }
-                }
-            };
-        }
-
-        @Override
-        public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            if (viewType == ITEM_TYPE_LAYOUT_DIVIDER) {
-                return new EmptyDocumentHolder(getContext());
-            };
-
-            DocumentHolder holder = null;
-            final State state = getDisplayState();
-            switch (state.derivedMode) {
-                case MODE_GRID:
-                    switch (viewType) {
-                        case ITEM_TYPE_DIRECTORY:
-                            holder = new GridDirectoryHolder(getContext(), parent);
-                            break;
-                        case ITEM_TYPE_DOCUMENT:
-                            holder = new GridDocumentHolder(getContext(), parent, mIconHelper);
-                            break;
-                        default:
-                            throw new IllegalStateException("Unsupported layout type.");
-                    }
-                    break;
-                case MODE_LIST:
-                    holder = new ListDocumentHolder(getContext(), parent, mIconHelper);
-                    break;
-                case MODE_UNKNOWN:
-                default:
-                    throw new IllegalStateException("Unsupported layout mode.");
-            }
-
-            holder.addClickListener(mItemClickListener);
-            holder.addOnKeyListener(mSelectionManager);
-            return holder;
-        }
-
-        /**
-         * Deal with selection changed events by using a custom ItemAnimator that just changes the
-         * background color.  This works around focus issues (otherwise items lose focus when their
-         * selection state changes) but also optimizes change animations for selection.
-         */
-        @Override
-        public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
-            if (holder.getItemViewType() == ITEM_TYPE_LAYOUT_DIVIDER) {
-                // Whitespace items are hidden elements with no data to bind.
-                return;
-            }
-
-            final View itemView = holder.itemView;
-
-            if (payload.contains(MultiSelectManager.SELECTION_CHANGED_MARKER)) {
-                final boolean selected = isSelected(mModelIds.get(position));
-                itemView.setActivated(selected);
-                return;
-            } else {
-                onBindViewHolder(holder, position);
-            }
-        }
-
-        @Override
-        public void onBindViewHolder(DocumentHolder holder, int position) {
-            if (holder.getItemViewType() == ITEM_TYPE_LAYOUT_DIVIDER) {
-                // Whitespace items are hidden elements with no data to bind.
-                return;
-            }
-
-            String modelId = mModelIds.get(position);
-            Cursor cursor = mModel.getItem(modelId);
-            holder.bind(cursor, modelId, getDisplayState());
-
-            final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
-            final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
-
-            holder.setSelected(isSelected(modelId));
-            holder.setEnabled(mTuner.isDocumentEnabled(docMimeType, docFlags));
-            if (DEBUG_ENABLE_DND) {
-                setupDragAndDropOnDocumentView(holder.itemView, cursor);
-            }
-        }
-
-        @Override
-        public int getItemCount() {
-            return mModelIds.size();
-        }
-
-        @Override
-        public void onModelUpdate(Model model) {
-            mModelIds = Lists.newArrayList(model.getModelIds());
-            // Start the divider at the end. That way if the code below encounters no documents
-            // (i.e. in a directory containing only directories), the divider is placed at the end
-            // of the list, as expected.
-            mDividerPosition = mModelIds.size();
-
-            // Walk down the list of IDs till we encounter something that's not a directory, and
-            // insert a whitespace element - this introduces a visual break in the grid between
-            // folders and documents.
-            // TODO: This code makes assumptions about the model, namely, that it performs a
-            // bucketed sort where directories will always be ordered before other files.  CBB.
-            for (int i = 0; i < mModelIds.size(); ++i) {
-                final String mimeType = getCursorString(
-                        model.getItem(mModelIds.get(i)), Document.COLUMN_MIME_TYPE);
-                if (!Document.MIME_TYPE_DIR.equals(mimeType)) {
-                    mDividerPosition = i;
-                    break;
-                }
-            }
-
-            mModelIds.add(mDividerPosition, null);
-        }
-
-        @Override
-        public void onModelUpdateFailed(Exception e) {
-            if (DEBUG) Log.d(TAG, "onModelUpdateFailed called ");
-            mModelIds.clear();
-        }
-
-        /**
-         * @return The model ID of the item at the given adapter position.
-         */
-        public String getModelId(int adapterPosition) {
-            return mModelIds.get(adapterPosition);
-        }
-
-        /**
-         * Hides a set of items from the associated RecyclerView.
-         *
-         * @param ids The Model IDs of the items to hide.
-         * @return A SparseArray that maps the hidden IDs to their old positions. This can be used
-         *         to {@link #unhide} the items if necessary.
-         */
-        public SparseArray<String> hide(String... ids) {
-            Set<String> toHide = Sets.newHashSet(ids);
-
-            // Proceed backwards through the list of items, because each removal causes the
-            // positions of all subsequent items to change.
-            SparseArray<String> hiddenItems = new SparseArray<>();
-            for (int i = mModelIds.size() - 1; i >= 0; --i) {
-                String id = mModelIds.get(i);
-                if (toHide.contains(id)) {
-                    hiddenItems.put(i, mModelIds.remove(i));
-                    notifyItemRemoved(i);
-                }
-            }
-
-            return hiddenItems;
-        }
-
-        /**
-         * Unhides a set of previously hidden items.
-         *
-         * @param ids A sparse array of IDs from a previous call to {@link #hide}.
-         */
-        public void unhide(SparseArray<String> ids) {
-            // Proceed backwards through the list of items, because each addition causes the
-            // positions of all subsequent items to change.
-            for (int i = ids.size() - 1; i >= 0; --i) {
-                int pos = ids.keyAt(i);
-                String id = ids.get(pos);
-                mModelIds.add(pos, id);
-                notifyItemInserted(pos);
-            }
-        }
-
-        /**
-         * Returns a list of model IDs of items currently in the adapter. Excludes items that are
-         * currently hidden (see {@link #hide(String...)}).
-         *
-         * @return A list of Model IDs.
-         */
-        public List<String> getModelIds() {
-            return mModelIds;
-        }
-
-        @Override
-        public int getItemViewType(int position) {
-            if (position < mDividerPosition) {
-                return ITEM_TYPE_DIRECTORY;
-            } else if (position == mDividerPosition) {
-                return ITEM_TYPE_LAYOUT_DIVIDER;
-            } else {
-                return ITEM_TYPE_DOCUMENT;
-            }
-        }
-
-        /**
-         * Triggers item-change notifications by stable ID. Passing an unrecognized ID will result
-         * in a warning in logcat, but no other error.
-         *
-         * @param id
-         * @param selectionChangedMarker
-         */
-        public void notifyItemChanged(String id, String selectionChangedMarker) {
-            int position = mModelIds.indexOf(id);
-
-            if (position >= 0) {
-                notifyItemChanged(position, selectionChangedMarker);
-            } else {
-                Log.w(TAG, "Item change notification received for unknown item: " + id);
-            }
-        }
-    }
-
     private String findCommonMimeType(List<String> mimeTypes) {
         String[] commonType = mimeTypes.get(0).split("/");
         if (commonType.length != 2) {
@@ -1504,7 +1305,8 @@
         abstract void onDocumentsReady(List<DocumentInfo> docs);
     }
 
-    boolean isSelected(String modelId) {
+    @Override
+    public boolean isSelected(String modelId) {
         return mSelectionManager.getSelection().contains(modelId);
     }
 
@@ -1520,7 +1322,7 @@
         }
     }
 
-    private class ModelUpdateListener implements Model.UpdateListener {
+    private final class ModelUpdateListener implements Model.UpdateListener {
         @Override
         public void onModelUpdate(Model model) {
             if (model.info != null || model.error != null) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
new file mode 100644
index 0000000..43c2f63
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/DocumentsAdapter.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView;
+import android.util.SparseArray;
+
+import com.android.documentsui.State;
+
+import java.nio.channels.UnsupportedAddressTypeException;
+import java.util.List;
+
+/**
+ * DocumentsAdapter provides glue between a directory Model, and RecylcerView. We've
+ * abstracted this a bit in order to decompose some specialized support
+ * for adding dummy layout objects (@see SectionBreakDocumentsAdapter). Handling of the
+ * dummy layout objects was error prone when interspersed with the core mode / adapter code.
+ *
+ * @see ModelBackedDocumentsAdapter
+ * @see SectionBreakDocumentsAdapter
+ */
+abstract class DocumentsAdapter
+        extends RecyclerView.Adapter<DocumentHolder>
+        implements Model.UpdateListener {
+
+    // Payloads for notifyItemChange to distinguish between selection and other events.
+    static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
+
+    /**
+     * Returns a list of model IDs of items currently in the adapter. Excludes items that are
+     * currently hidden (see {@link #hide(String...)}).
+     *
+     * @return A list of Model IDs.
+     */
+    abstract List<String> getModelIds();
+
+    /**
+     * Triggers item-change notifications by stable ID (as opposed to position).
+     * Passing an unrecognized ID will result in a warning in logcat, but no other error.
+     */
+    abstract void onItemSelectionChanged(String id);
+
+    /**
+     * @return The model ID of the item at the given adapter position.
+     */
+    abstract String getModelId(int position);
+
+    /**
+     * Hides a set of items from the associated RecyclerView.
+     *
+     * @param ids The Model IDs of the items to hide.
+     * @return A SparseArray that maps the hidden IDs to their old positions. This can be used
+     *         to {@link #unhide} the items if necessary.
+     */
+    abstract public SparseArray<String> hide(String... ids);
+
+    /**
+     * Unhides a set of previously hidden items.
+     *
+     * @param ids A sparse array of IDs from a previous call to {@link #hide}.
+     */
+    abstract void unhide(SparseArray<String> ids);
+
+    /**
+     * Returns a class that yields the span size for a particular element. This is
+     * primarily useful in {@link SectionBreakDocumentsAdapterWrapper} where
+     * we adjust sizes.
+     */
+    GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+        throw new UnsupportedAddressTypeException();
+    }
+
+    static boolean isDirectory(Cursor cursor) {
+        final String mimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        return Document.MIME_TYPE_DIR.equals(mimeType);
+    }
+
+    boolean isDirectory(Model model, int position) {
+        String modelId = getModelIds().get(position);
+        Cursor cursor = model.getItem(modelId);
+        return isDirectory(cursor);
+    }
+
+    /**
+     * Environmental access for View adapter implementations.
+     */
+    interface Environment {
+        Context getContext();
+        int getColumnCount();
+        State getDisplayState();
+        boolean isSelected(String id);
+        Model getModel();
+        boolean isDocumentEnabled(String mimeType, int flags);
+        void initDocumentHolder(DocumentHolder holder);
+        void onBindDocumentHolder(DocumentHolder holder, Cursor cursor);
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
index bea38c6..f2bade5 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/Model.java
@@ -35,7 +35,6 @@
 import android.provider.DocumentsContract.Document;
 import android.support.annotation.Nullable;
 import android.support.annotation.VisibleForTesting;
-import android.support.v7.widget.RecyclerView;
 import android.util.Log;
 
 import com.android.documentsui.BaseActivity.SiblingProvider;
@@ -74,7 +73,7 @@
     @Nullable String info;
     @Nullable String error;
 
-    Model(Context context, RecyclerView.Adapter<?> viewAdapter) {
+    Model(Context context) {
         mContext = context;
     }
 
@@ -87,8 +86,19 @@
     private static String createModelId(Cursor c) {
         // TODO: Maybe more efficient to use just the document ID, in cases where there is only one
         // authority (which should be the majority of cases).
-        return getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY) +
-                "|" + getCursorString(c, Document.COLUMN_DOCUMENT_ID);
+        return createModelId(
+                getCursorString(c, RootCursorWrapper.COLUMN_AUTHORITY),
+                getCursorString(c, Document.COLUMN_DOCUMENT_ID));
+    }
+
+    /**
+     * Generates a Model ID for a cursor entry that refers to a document. The Model ID is a unique
+     * string that can be used to identify the document referred to by the cursor.
+     *
+     * @param c A cursor that refers to a document.
+     */
+    static String createModelId(String authority, String docId) {
+        return authority + "|" + docId;
     }
 
     private void notifyUpdateListeners() {
@@ -404,8 +414,14 @@
 
         @Override
         protected Void doInBackground(Selection... selected) {
-            List<DocumentInfo> toDelete = getDocuments(selected[0]);
-            mHadTrouble = false;
+            List<DocumentInfo> toDelete = null;
+            try {
+                toDelete = getDocuments(selected[0]);
+            } catch (NullPointerException e) {
+                Log.w(TAG, "Failed to retrieve documents for delete.");
+                mHadTrouble = true;
+                return null;
+            }
 
             for (DocumentInfo doc : toDelete) {
                 if (!doc.isDeleteSupported()) {
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
new file mode 100644
index 0000000..68756a3
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapter.java
@@ -0,0 +1,230 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.documentsui.Shared.DEBUG;
+import static com.android.documentsui.State.MODE_GRID;
+import static com.android.documentsui.State.MODE_LIST;
+import static com.android.documentsui.State.MODE_UNKNOWN;
+import static com.android.documentsui.model.DocumentInfo.getCursorInt;
+import static com.android.documentsui.model.DocumentInfo.getCursorString;
+
+import android.database.Cursor;
+import android.provider.DocumentsContract.Document;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import com.google.common.collect.Sets;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Adapts from dirlist.Model to something RecyclerView understands.
+ */
+final class ModelBackedDocumentsAdapter extends DocumentsAdapter {
+
+    private static final String TAG = "ModelBackedDocumentsAdapter";
+    public static final int ITEM_TYPE_DOCUMENT = 1;
+    public static final int ITEM_TYPE_DIRECTORY = 2;
+
+    // Provides access to information needed when creating and view holders. This
+    // isn't an ideal pattern (more transitive dependency stuff) but good enough for now.
+    private final Environment mEnv;
+    private final IconHelper mIconHelper;  // a transitive dependency of the holders.
+
+    /**
+     * An ordered list of model IDs. This is the data structure that determines what shows up in
+     * the UI, and where.
+     */
+    private List<String> mModelIds = new ArrayList<>();
+
+    // List of files that have been deleted. Some transient directory updates
+    // may happen while files are being deleted. During this time we don't
+    // want once-hidden files to be re-shown. We only remove
+    // items from this list when we get a model update where the model
+    // does not contain a corresponding id. This ensures hidden entries
+    // don't momentarily re-appear if we get intermediate updates from
+    // the file system.
+    private Set<String> mHiddenIds = new HashSet<>();
+
+    public ModelBackedDocumentsAdapter(Environment env, IconHelper iconHelper) {
+        mEnv = env;
+        mIconHelper = iconHelper;
+    }
+
+    @Override
+    public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        DocumentHolder holder = null;
+        final State state = mEnv.getDisplayState();
+        switch (state.derivedMode) {
+            case MODE_GRID:
+                switch (viewType) {
+                    case ITEM_TYPE_DIRECTORY:
+                        holder = new GridDirectoryHolder(mEnv.getContext(), parent);
+                        break;
+                    case ITEM_TYPE_DOCUMENT:
+                        holder = new GridDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+                        break;
+                    default:
+                        throw new IllegalStateException("Unsupported layout type.");
+                }
+                break;
+            case MODE_LIST:
+                holder = new ListDocumentHolder(mEnv.getContext(), parent, mIconHelper);
+                break;
+            case MODE_UNKNOWN:
+            default:
+                throw new IllegalStateException("Unsupported layout mode.");
+        }
+
+        mEnv.initDocumentHolder(holder);
+        return holder;
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int position, List<Object> payload) {
+        if (payload.contains(SELECTION_CHANGED_MARKER)) {
+            final boolean selected = mEnv.isSelected(mModelIds.get(position));
+            holder.setSelected(selected);
+        } else {
+            onBindViewHolder(holder, position);
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int position) {
+        String modelId = mModelIds.get(position);
+        Cursor cursor = mEnv.getModel().getItem(modelId);
+        holder.bind(cursor, modelId, mEnv.getDisplayState());
+
+        final String docMimeType = getCursorString(cursor, Document.COLUMN_MIME_TYPE);
+        final int docFlags = getCursorInt(cursor, Document.COLUMN_FLAGS);
+
+        holder.setSelected(mEnv.isSelected(modelId));
+        holder.setEnabled(mEnv.isDocumentEnabled(docMimeType, docFlags));
+
+        mEnv.onBindDocumentHolder(holder, cursor);
+    }
+
+    @Override
+    public int getItemCount() {
+        return mModelIds.size();
+    }
+
+    @Override
+    public void onModelUpdate(Model model) {
+        if (DEBUG && mHiddenIds.size() > 0) {
+            Log.d(TAG, "Updating model with hidden ids: " + mHiddenIds);
+        }
+
+        List<String> modelIds = model.getModelIds();
+        mModelIds = new ArrayList<>(modelIds.size());
+        for (String id : modelIds) {
+            if (!mHiddenIds.contains(id)) {
+                mModelIds.add(id);
+            } else {
+                if (DEBUG) Log.d(TAG, "Omitting hidden id from model during update: " + id);
+            }
+        }
+
+        // Finally remove any hidden ids that aren't present in the model.
+        // This assumes that model updates represent a complete set of files.
+        mHiddenIds.retainAll(mModelIds);
+    }
+
+    @Override
+    public void onModelUpdateFailed(Exception e) {
+        Log.w(TAG, "Model update failed.", e);
+        mModelIds.clear();
+    }
+
+    @Override
+    public String getModelId(int adapterPosition) {
+        return mModelIds.get(adapterPosition);
+    }
+
+    @Override
+    public SparseArray<String> hide(String... ids) {
+        if (DEBUG) Log.d(TAG, "Hiding ids: " + ids);
+        Set<String> toHide = Sets.newHashSet(ids);
+
+        // Proceed backwards through the list of items, because each removal causes the
+        // positions of all subsequent items to change.
+        SparseArray<String> hiddenItems = new SparseArray<>();
+        for (int i = mModelIds.size() - 1; i >= 0; --i) {
+            String id = mModelIds.get(i);
+            if (toHide.contains(id)) {
+                mHiddenIds.add(id);
+                hiddenItems.put(i, mModelIds.remove(i));
+                notifyItemRemoved(i);
+            }
+        }
+
+        return hiddenItems;
+    }
+
+    @Override
+    public void unhide(SparseArray<String> ids) {
+        if (DEBUG) Log.d(TAG, "Un-iding ids: " + ids);
+
+        // An ArrayList can shrink at runtime...and in fact
+        // it does when we clear it completely.
+        // This means we can't call add(pos, id) without
+        // first checking the list size.
+        List<String> oldIds = mModelIds;
+        mModelIds = new ArrayList<>(oldIds.size() + ids.size());
+        mModelIds.addAll(oldIds);
+
+        // Finally insert the unhidden items.
+        for (int i = 0; i < ids.size(); i++) {
+            int pos = ids.keyAt(i);
+            String id = ids.get(pos);
+            mHiddenIds.remove(id);
+            mModelIds.add(pos, id);
+            notifyItemInserted(pos);
+        }
+    }
+
+    @Override
+    public List<String> getModelIds() {
+        return mModelIds;
+    }
+
+    @Override
+    public int getItemViewType(int position) {
+        return isDirectory(mEnv.getModel(), position)
+                ? ITEM_TYPE_DIRECTORY
+                : ITEM_TYPE_DOCUMENT;
+    }
+
+    @Override
+    public void onItemSelectionChanged(String id) {
+        int position = mModelIds.indexOf(id);
+
+        if (position >= 0) {
+            notifyItemChanged(position, SELECTION_CHANGED_MARKER);
+        } else {
+            Log.w(TAG, "Item change notification received for unknown item: " + id);
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
index e47af67..5994df9 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/MultiSelectManager.java
@@ -68,24 +68,23 @@
 
     private final Selection mSelection = new Selection();
 
-    private Range mRanger;
-    private SelectionEnvironment mEnvironment;
-
+    private final SelectionEnvironment mEnvironment;
+    private final DocumentsAdapter mAdapter;
     private final List<MultiSelectManager.Callback> mCallbacks = new ArrayList<>(1);
 
+    private Range mRanger;
     private boolean mSingleSelect;
 
-    // Payloads for notifyItemChange to distinguish between selection and other events.
-    public static final String SELECTION_CHANGED_MARKER = "Selection-Changed";
-
     @Nullable private BandController mBandManager;
 
+
     /**
      * @param recyclerView
      * @param mode Selection mode
      */
-    public MultiSelectManager(final RecyclerView recyclerView, int mode) {
-        this(new RuntimeSelectionEnvironment(recyclerView), mode);
+    public MultiSelectManager(
+            final RecyclerView recyclerView, DocumentsAdapter adapter, int mode) {
+        this(new RuntimeSelectionEnvironment(recyclerView), adapter, mode);
 
         if (mode == MODE_MULTIPLE) {
             mBandManager = new BandController();
@@ -136,11 +135,12 @@
      * @hide
      */
     @VisibleForTesting
-    MultiSelectManager(SelectionEnvironment environment, int mode) {
+    MultiSelectManager(SelectionEnvironment environment, DocumentsAdapter adapter, int mode) {
         mEnvironment = checkNotNull(environment, "'environment' cannot be null.");
+        mAdapter = checkNotNull(adapter, "'adapter' cannot be null.");
         mSingleSelect = mode == MODE_SINGLE;
 
-        mEnvironment.registerDataObserver(
+        mAdapter.registerAdapterDataObserver(
                 new RecyclerView.AdapterDataObserver() {
 
                     private List<String> mModelIds;
@@ -149,7 +149,7 @@
                     public void onChanged() {
                         // TODO: This is causing b/22765812
                         mSelection.clear();
-                        mModelIds = mEnvironment.getModelIds();
+                        mModelIds = mAdapter.getModelIds();
                     }
 
                     @Override
@@ -339,7 +339,10 @@
             if (DEBUG) Log.d(TAG, "Ignoring toggle for element with no position.");
             return;
         }
-        toggleSelection(mEnvironment.getModelIdFromAdapterPosition(position));
+        String id = mAdapter.getModelId(position);
+        if (id != null) {
+            toggleSelection(id);
+        }
     }
 
     /**
@@ -348,6 +351,7 @@
      * @param modelId
      */
     public void toggleSelection(String modelId) {
+        checkNotNull(modelId);
         boolean changed = false;
         if (mSelection.contains(modelId)) {
             changed = attemptDeselect(modelId);
@@ -387,7 +391,7 @@
             return;
         }
 
-        if (mSelection.contains(mEnvironment.getModelIdFromAdapterPosition(position))) {
+        if (mSelection.contains(mAdapter.getModelId(position))) {
             mRanger = new Range(position);
         }
     }
@@ -404,7 +408,11 @@
     private void updateRange(int begin, int end, boolean selected) {
         checkState(end >= begin);
         for (int i = begin; i <= end; i++) {
-            String id = mEnvironment.getModelIdFromAdapterPosition(i);
+            String id = mAdapter.getModelId(i);
+            if (id == null) {
+                continue;
+            }
+
             if (selected) {
                 boolean canSelect = notifyBeforeItemStateChange(id, true);
                 if (canSelect) {
@@ -436,6 +444,7 @@
      * @return True if the update was applied.
      */
     private boolean attemptDeselect(String id) {
+        checkArgument(id != null);
         if (notifyBeforeItemStateChange(id, false)) {
             mSelection.remove(id);
             notifyItemStateChanged(id, false);
@@ -462,11 +471,12 @@
      * (identified by {@code position}) changes.
      */
     private void notifyItemStateChanged(String id, boolean selected) {
+        checkArgument(id != null);
         int lastListener = mCallbacks.size() - 1;
         for (int i = lastListener; i > -1; i--) {
             mCallbacks.get(i).onItemStateChanged(id, selected);
         }
-        mEnvironment.notifyItemChanged(id);
+        mAdapter.onItemSelectionChanged(id);
     }
 
     /**
@@ -613,7 +623,7 @@
          * @param id
          * @return true if the position is currently selected.
          */
-        public boolean contains(String id) {
+        public boolean contains(@Nullable String id) {
             return mTotalSelection.contains(id);
         }
 
@@ -804,11 +814,6 @@
         int getChildCount();
         int getVisibleChildCount();
         void focusItem(int position);
-        String getModelIdFromAdapterPosition(int position);
-        int getItemCount();
-        List<String> getModelIds();
-        void notifyItemChanged(String id);
-        void registerDataObserver(RecyclerView.AdapterDataObserver observer);
     }
 
     /** Recycler view facade implementation backed by good ol' RecyclerView. */
@@ -818,11 +823,9 @@
         private final Drawable mBand;
 
         private boolean mIsOverlayShown = false;
-        private DirectoryFragment.DocumentsAdapter mAdapter;
 
-        RuntimeSelectionEnvironment(RecyclerView rv) {
-            mView = rv;
-            mAdapter = (DirectoryFragment.DocumentsAdapter) rv.getAdapter();
+        RuntimeSelectionEnvironment(RecyclerView view) {
+            mView = view;
             mBand = mView.getContext().getTheme().getDrawable(R.drawable.band_select_overlay);
         }
 
@@ -841,11 +844,6 @@
         }
 
         @Override
-        public String getModelIdFromAdapterPosition(int position) {
-            return mAdapter.getModelId(position);
-        }
-
-        @Override
         public void addOnScrollListener(RecyclerView.OnScrollListener listener) {
             mView.addOnScrollListener(listener);
         }
@@ -961,26 +959,6 @@
                     });
             }
         }
-
-        @Override
-        public void notifyItemChanged(String id) {
-            mAdapter.notifyItemChanged(id, SELECTION_CHANGED_MARKER);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mAdapter.getItemCount();
-        }
-
-        @Override
-        public void registerDataObserver(RecyclerView.AdapterDataObserver observer) {
-            mAdapter.registerAdapterDataObserver(observer);
-        }
-
-        @Override
-        public List<String> getModelIds() {
-            return mAdapter.getModelIds();
-        }
     }
 
     public interface Callback {
@@ -1037,7 +1015,7 @@
             mModelBuilder = new Runnable() {
                 @Override
                 public void run() {
-                    mModel = new GridModel(mEnvironment);
+                    mModel = new GridModel(mEnvironment, mAdapter);
                     mModel.addOnSelectionChangedListener(BandController.this);
                 }
             };
@@ -1088,7 +1066,7 @@
             return !isActive()
                     && e.isMouseEvent()  // a mouse
                     && e.isActionDown()  // the initial button press
-                    && mEnvironment.getItemCount() > 0
+                    && mAdapter.getItemCount() > 0
                     && e.getItemPosition() == RecyclerView.NO_ID;  // in empty space
         }
 
@@ -1165,7 +1143,7 @@
             mModel.endSelection();
             int firstSelected = mModel.getPositionNearestOrigin();
             if (firstSelected != NOT_SET) {
-                if (mSelection.contains(mEnvironment.getModelIdFromAdapterPosition(firstSelected))) {
+                if (mSelection.contains(mAdapter.getModelId(firstSelected))) {
                     // TODO: firstSelected should really be lastSelected, we want to anchor the item
                     // where the mouse-up occurred.
                     setSelectionRangeBegin(firstSelected);
@@ -1327,6 +1305,8 @@
         private static final int LOWER_RIGHT = LOWER | RIGHT;
 
         private final SelectionEnvironment mHelper;
+        private final DocumentsAdapter mAdapter;
+
         private final List<OnSelectionChangedListener> mOnSelectionChangedListeners =
                 new ArrayList<>();
 
@@ -1364,8 +1344,9 @@
         // should expand from when Shift+click is used.
         private int mPositionNearestOrigin = NOT_SET;
 
-        GridModel(SelectionEnvironment helper) {
+        GridModel(SelectionEnvironment helper, DocumentsAdapter adapter) {
             mHelper = helper;
+            mAdapter = adapter;
             mHelper.addOnScrollListener(this);
         }
 
@@ -1568,7 +1549,7 @@
                     // position. Use a sentry value to prevent erroneously selecting item 0.
                     int position = items.get(items.keyAt(row), NOT_SET);
                     if (position != NOT_SET) {
-                        String id = mHelper.getModelIdFromAdapterPosition(position);
+                        String id = mAdapter.getModelId(position);
                         if (id != null) {
                             // The adapter inserts items for UI layout purposes that aren't associated
                             // with files.  Those will have a null model ID.  Don't select them.
@@ -1977,7 +1958,7 @@
         if (keyCode == KeyEvent.KEYCODE_MOVE_HOME) {
             position = 0;
         } else if (keyCode == KeyEvent.KEYCODE_MOVE_END) {
-            position = mEnvironment.getItemCount() - 1;
+            position = mAdapter.getItemCount() - 1;
         } else {
             // Find a navigation target based on the arrow key that the user pressed.  Ignore
             // navigation targets that aren't items in the recycler view.
diff --git a/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
new file mode 100644
index 0000000..b4782f0
--- /dev/null
+++ b/packages/DocumentsUI/src/com/android/documentsui/dirlist/SectionBreakDocumentsAdapterWrapper.java
@@ -0,0 +1,217 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import static com.android.internal.util.Preconditions.checkArgument;
+
+import android.support.v7.widget.GridLayoutManager;
+import android.support.v7.widget.RecyclerView.AdapterDataObserver;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.List;
+
+/**
+ * Adapter wrapper that inserts a sort of line break item between directories and regular files.
+ * Only needs to be used in GRID mode...at this time.
+ */
+final class SectionBreakDocumentsAdapterWrapper extends DocumentsAdapter {
+
+    private static final String TAG = "SectionBreakDocumentsAdapterWrapper";
+    private static final int ITEM_TYPE_SECTION_BREAK = Integer.MAX_VALUE;
+
+    private final Environment mEnv;
+    private final DocumentsAdapter mDelegate;
+
+    private int mBreakPosition = -1;
+
+    SectionBreakDocumentsAdapterWrapper(Environment environment, DocumentsAdapter delegate) {
+        mEnv = environment;
+        mDelegate = delegate;
+
+        // Relay events published by our delegate to our listeners (presumably RecyclerView)
+        // with adjusted positions.
+        mDelegate.registerAdapterDataObserver(new EventRelay());
+    }
+
+    public GridLayoutManager.SpanSizeLookup createSpanSizeLookup() {
+        return new GridLayoutManager.SpanSizeLookup() {
+            @Override
+            public int getSpanSize(int position) {
+                // Make layout whitespace span the grid. This has the effect of breaking
+                // grid rows whenever layout whitespace is encountered.
+                if (getItemViewType(position) == ITEM_TYPE_SECTION_BREAK) {
+                    return mEnv.getColumnCount();
+                } else {
+                    return 1;
+                }
+            }
+        };
+    }
+
+    @Override
+    public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        if (viewType == ITEM_TYPE_SECTION_BREAK) {
+            return new EmptyDocumentHolder(mEnv.getContext());
+        } else {
+            return mDelegate.createViewHolder(parent, viewType);
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int p, List<Object> payload) {
+        if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+            mDelegate.onBindViewHolder(holder, toDelegatePosition(p), payload);
+        }
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int p) {
+        if (holder.getItemViewType() != ITEM_TYPE_SECTION_BREAK) {
+            mDelegate.onBindViewHolder(holder, toDelegatePosition(p));
+        }
+    }
+
+    @Override
+    public int getItemCount() {
+        return mBreakPosition == -1
+                ? mDelegate.getItemCount()
+                : mDelegate.getItemCount() + 1;
+    }
+
+    @Override
+    public void onModelUpdate(Model model) {
+        mDelegate.onModelUpdate(model);
+        mBreakPosition = -1;
+
+        // Walk down the list of IDs till we encounter something that's not a directory, and
+        // insert a whitespace element - this introduces a visual break in the grid between
+        // folders and documents.
+        // TODO: This code makes assumptions about the model, namely, that it performs a
+        // bucketed sort where directories will always be ordered before other files. CBB.
+        List<String> modelIds = mDelegate.getModelIds();
+        for (int i = 0; i < modelIds.size(); i++) {
+            if (!isDirectory(model, i)) {
+                mBreakPosition = i;
+                break;
+            }
+        }
+    }
+
+    @Override
+    public void onModelUpdateFailed(Exception e) {
+        mDelegate.onModelUpdateFailed(e);
+    }
+
+    @Override
+    public int getItemViewType(int p) {
+        if (p == mBreakPosition) {
+            return ITEM_TYPE_SECTION_BREAK;
+        } else {
+            return mDelegate.getItemViewType(toDelegatePosition(p));
+        }
+    }
+
+    /**
+     * Returns the position of an item in the delegate, adjusting
+     * values that are greater than the break position.
+     *
+     * @param p Position within the view
+     * @return Position within the delegate
+     */
+    private int toDelegatePosition(int p) {
+        return (mBreakPosition != -1 && p > mBreakPosition) ? p - 1 : p;
+    }
+
+    /**
+     * Returns the position of an item in the view, adjusting
+     * values that are greater than the break position.
+     *
+     * @param p Position within the delegate
+     * @return Position within the view
+     */
+    private int toViewPosition(int p) {
+        // If position is greater than or equal to the break, increase by one.
+        return (mBreakPosition != -1 && p >= mBreakPosition) ? p + 1 : p;
+    }
+
+    @Override
+    public SparseArray<String> hide(String... ids) {
+        // NOTE: We hear about these changes and adjust break position
+        // in our AdapterDataObserver.
+        return mDelegate.hide(ids);
+    }
+
+    @Override
+    void unhide(SparseArray<String> ids) {
+        // NOTE: We hear about these changes and adjust break position
+        // in our AdapterDataObserver.
+        mDelegate.unhide(ids);
+    }
+
+    @Override
+    List<String> getModelIds() {
+        return mDelegate.getModelIds();
+    }
+
+    @Override
+    String getModelId(int p) {
+        return (p == mBreakPosition) ? null : mDelegate.getModelId(toDelegatePosition(p));
+    }
+
+    @Override
+    public void onItemSelectionChanged(String id) {
+        mDelegate.onItemSelectionChanged(id);
+    }
+
+    // Listener we add to our delegate. This allows us to relay events published
+    // by the delegate to our listeners (presumably RecyclerView) with adjusted positions.
+    private final class EventRelay extends AdapterDataObserver {
+        public void onChanged() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onItemRangeChanged(int positionStart, int itemCount) {
+            throw new UnsupportedOperationException();
+        }
+
+        public void onItemRangeChanged(int positionStart, int itemCount, Object payload) {
+            checkArgument(itemCount == 1);
+            notifyItemRangeChanged(toViewPosition(positionStart), itemCount, payload);
+        }
+
+        public void onItemRangeInserted(int positionStart, int itemCount) {
+            checkArgument(itemCount == 1);
+            if (positionStart < mBreakPosition) {
+                mBreakPosition++;
+            }
+            notifyItemRangeInserted(toViewPosition(positionStart), itemCount);
+        }
+
+        public void onItemRangeRemoved(int positionStart, int itemCount) {
+            checkArgument(itemCount == 1);
+            if (positionStart < mBreakPosition) {
+                mBreakPosition--;
+            }
+            notifyItemRangeRemoved(toViewPosition(positionStart), itemCount);
+        }
+
+        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {
+            throw new UnsupportedOperationException();
+        }
+    }
+}
diff --git a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
index 4caa891..12c0b8f 100644
--- a/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
+++ b/packages/DocumentsUI/src/com/android/documentsui/model/RootInfo.java
@@ -174,7 +174,7 @@
             derivedIcon = R.drawable.ic_root_home;
             derivedType = TYPE_LOCAL;
         } else if (isExternalStorage()) {
-            derivedIcon = R.drawable.ic_root_sdcard;
+            derivedIcon = R.drawable.ic_root_smartphone;
             derivedType = TYPE_LOCAL;
         } else if (isDownloads()) {
             derivedIcon = R.drawable.ic_root_download;
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
new file mode 100644
index 0000000..5ce1823
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelBackedDocumentsAdapterTest.java
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.content.Context;
+import android.database.Cursor;
+import android.support.v7.widget.RecyclerView;
+import android.test.AndroidTestCase;
+import android.test.suitebuilder.annotation.SmallTest;
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import com.android.documentsui.State;
+
+import java.util.List;
+
+@SmallTest
+public class ModelBackedDocumentsAdapterTest extends AndroidTestCase {
+
+    private static final String AUTHORITY = "test_authority";
+    private static final String[] NAMES = new String[] {
+            "4",
+            "foo",
+            "1",
+            "bar",
+            "*(Ljifl;a",
+            "0",
+            "baz",
+            "2",
+            "3",
+            "%$%VD"
+    };
+
+    private TestModel mModel;
+    private ModelBackedDocumentsAdapter mAdapter;
+
+    public void setUp() {
+
+        final Context testContext = TestContext.createStorageTestContext(getContext(), AUTHORITY);
+        mModel = new TestModel(testContext, AUTHORITY);
+        mModel.update(NAMES);
+
+        DocumentsAdapter.Environment env = new TestEnvironment(testContext);
+
+        mAdapter = new ModelBackedDocumentsAdapter(
+                env, new IconHelper(testContext, State.MODE_GRID));
+        mAdapter.onModelUpdate(mModel);
+    }
+
+    // Tests that the item count is correct.
+    public void testItemCount() {
+        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+    }
+
+    // Tests that the item count is correct.
+    public void testHide_ItemCount() {
+        List<String> ids = mModel.getModelIds();
+        mAdapter.hide(ids.get(0), ids.get(1));
+        assertEquals(mModel.getItemCount() - 2, mAdapter.getItemCount());
+    }
+
+    // Tests that the items can be hidden and unhidden.
+    public void testUnhide_ItemCount() {
+        List<String> ids = mModel.getModelIds();
+        SparseArray<String> hidden = mAdapter.hide(ids.toArray(new String[ids.size()]));
+        mAdapter.unhide(hidden);
+        assertEquals(mModel.getItemCount(), mAdapter.getItemCount());
+    }
+
+    // Tests that the items can be hidden and unhidden.
+    public void testUnhide_PreservesOrder() {
+        List<String> ids = mModel.getModelIds();
+        SparseArray<String> hidden = mAdapter.hide(
+                ids.get(0), ids.get(1), ids.get(5), ids.get(9));
+        mAdapter.unhide(hidden);
+
+        // Finally ensure the restored items are in the original order
+        // by checking them against the model.
+        for (int i = 0; i < mAdapter.getItemCount(); i++) {
+            assertEquals(mModel.idForPosition(i), mAdapter.getModelId(i));
+        }
+    }
+
+    private final class TestEnvironment implements DocumentsAdapter.Environment {
+        private final Context testContext;
+
+        private TestEnvironment(Context testContext) {
+            this.testContext = testContext;
+        }
+
+        @Override
+        public boolean isSelected(String id) {
+            return false;
+        }
+
+        @Override
+        public boolean isDocumentEnabled(String mimeType, int flags) {
+            return true;
+        }
+
+        @Override
+        public void initDocumentHolder(DocumentHolder holder) {}
+
+        @Override
+        public Model getModel() {
+            return mModel;
+        }
+
+        @Override
+        public State getDisplayState() {
+            return null;
+        }
+
+        @Override
+        public Context getContext() {
+            return testContext;
+        }
+
+        @Override
+        public int getColumnCount() {
+            return 4;
+        }
+
+        @Override
+        public void onBindDocumentHolder(DocumentHolder holder, Cursor cursor) {}
+    }
+
+    private static class DummyListener implements Model.UpdateListener {
+        public void onModelUpdate(Model model) {}
+        public void onModelUpdateFailed(Exception e) {}
+    }
+
+    private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
+        public int getItemCount() { return 0; }
+        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
+        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+            return null;
+        }
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
index 121eb41..bed7c9c 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/ModelTest.java
@@ -21,16 +21,10 @@
 import android.content.ContextWrapper;
 import android.database.Cursor;
 import android.database.MatrixCursor;
-import android.net.Uri;
-import android.os.Bundle;
-import android.provider.DocumentsContract;
 import android.provider.DocumentsContract.Document;
-import android.support.v7.widget.RecyclerView;
 import android.test.AndroidTestCase;
-import android.test.mock.MockContentProvider;
 import android.test.mock.MockContentResolver;
 import android.test.suitebuilder.annotation.SmallTest;
-import android.view.ViewGroup;
 
 import com.android.documentsui.DirectoryResult;
 import com.android.documentsui.RootCursorWrapper;
@@ -49,6 +43,7 @@
 
     private static final int ITEM_COUNT = 10;
     private static final String AUTHORITY = "test_authority";
+
     private static final String[] COLUMNS = new String[]{
         RootCursorWrapper.COLUMN_AUTHORITY,
         Document.COLUMN_DOCUMENT_ID,
@@ -57,23 +52,24 @@
         Document.COLUMN_SIZE,
         Document.COLUMN_MIME_TYPE
     };
-    private static Cursor cursor;
 
+    private static final String[] NAMES = new String[] {
+            "4",
+            "foo",
+            "1",
+            "bar",
+            "*(Ljifl;a",
+            "0",
+            "baz",
+            "2",
+            "3",
+            "%$%VD"
+        };
+
+    private Cursor cursor;
     private Context context;
     private Model model;
     private TestContentProvider provider;
-    private static final String[] NAMES = new String[] {
-        "4",
-        "foo",
-        "1",
-        "bar",
-        "*(Ljifl;a",
-        "0",
-        "baz",
-        "2",
-        "3",
-        "%$%VD"
-    };
 
     public void setUp() {
         setupTestContext();
@@ -97,7 +93,7 @@
         r.cursor = cursor;
 
         // Instantiate the model with a dummy view adapter and listener that (for now) do nothing.
-        model = new Model(context, new DummyAdapter());
+        model = new Model(context);
         model.addUpdateListener(new DummyListener());
         model.update(r);
     }
@@ -326,32 +322,4 @@
         public void onModelUpdate(Model model) {}
         public void onModelUpdateFailed(Exception e) {}
     }
-
-    private static class DummyAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
-        public int getItemCount() { return 0; }
-        public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {}
-        public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
-            return null;
-        }
-    }
-
-    private static class TestContentProvider extends MockContentProvider {
-        List<Uri> mDeleted = new ArrayList<>();
-
-        @Override
-        public Bundle call(String method, String arg, Bundle extras) {
-            // Intercept and log delete method calls.
-            if (DocumentsContract.METHOD_DELETE_DOCUMENT.equals(method)) {
-                final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
-                mDeleted.add(documentUri);
-                return new Bundle();
-            } else {
-                return super.call(method, arg, extras);
-            }
-        }
-
-        public void assertWasDeleted(DocumentInfo doc) {
-            assertTrue(mDeleted.contains(doc.derivedUri));
-        }
-    }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
index 5989135..e06199e 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManagerTest.java
@@ -23,6 +23,7 @@
 
 import com.android.documentsui.TestInputEvent;
 import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+
 import com.google.common.collect.Lists;
 
 import java.util.ArrayList;
@@ -44,11 +45,13 @@
     private MultiSelectManager mManager;
     private TestCallback mCallback;
     private TestSelectionEnvironment mEnv;
+    private TestDocumentsAdapter mAdapter;
 
     public void setUp() throws Exception {
         mCallback = new TestCallback();
         mEnv = new TestSelectionEnvironment(items);
-        mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_MULTIPLE);
+        mAdapter = new TestDocumentsAdapter(items);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_MULTIPLE);
         mManager.addCallback(mCallback);
     }
 
@@ -164,7 +167,7 @@
     }
 
     public void testSingleSelectMode() {
-        mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_SINGLE);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(20);
         tap(13);
@@ -172,7 +175,7 @@
     }
 
     public void testSingleSelectMode_ShiftTap() {
-        mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_SINGLE);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(13);
         shiftTap(20);
@@ -180,7 +183,7 @@
     }
 
     public void testSingleSelectMode_ShiftDoesNotExtendSelection() {
-        mManager = new MultiSelectManager(mEnv, MultiSelectManager.MODE_SINGLE);
+        mManager = new MultiSelectManager(mEnv, mAdapter, MultiSelectManager.MODE_SINGLE);
         mManager.addCallback(mCallback);
         longPress(20);
         keyToPosition(22, true);
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
index 3d6923f..5c04db9 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/MultiSelectManager_GridModelTest.java
@@ -20,7 +20,6 @@
 
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView.AdapterDataObserver;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
 import android.test.AndroidTestCase;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -28,7 +27,7 @@
 
 import com.android.documentsui.dirlist.MultiSelectManager.GridModel;
 
-import java.util.List;
+import java.util.ArrayList;
 import java.util.Set;
 
 @SmallTest
@@ -38,15 +37,28 @@
     private static final int CHILD_VIEW_EDGE_PX = 100;
     private static final int VIEWPORT_HEIGHT = 500;
 
-    private static GridModel model;
-    private static TestEnvironment env;
-    private static Set<String> lastSelection;
-    private static int viewWidth;
+    private GridModel model;
+    private TestEnvironment env;
+    private TestDocumentsAdapter adapter;
+    private Set<String> lastSelection;
+    private int viewWidth;
 
-    private static void setUp(int numChildren, int numColumns) {
+    private void initData(final int numChildren, int numColumns) {
         env = new TestEnvironment(numChildren, numColumns);
+        adapter = new TestDocumentsAdapter(new ArrayList<String>()) {
+            @Override
+            public String getModelId(int position) {
+                return Integer.toString(position);
+            }
+
+            @Override
+            public int getItemCount() {
+                return numChildren;
+            }
+        };
+
         viewWidth = VIEW_PADDING_PX + numColumns * (VIEW_PADDING_PX + CHILD_VIEW_EDGE_PX);
-        model = new GridModel(env);
+        model = new GridModel(env, adapter);
         model.addOnSelectionChangedListener(
                 new GridModel.OnSelectionChangedListener() {
                     @Override
@@ -64,7 +76,7 @@
     }
 
     public void testSelectionLeftOfItems() {
-        setUp(20, 5);
+        initData(20, 5);
         model.startSelection(new Point(0, 10));
         model.resizeSelection(new Point(1, 11));
         assertSelected();
@@ -72,7 +84,7 @@
     }
 
     public void testSelectionRightOfItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(viewWidth - 1, 10));
         model.resizeSelection(new Point(viewWidth - 2, 11));
         assertSelected();
@@ -80,7 +92,7 @@
     }
 
     public void testSelectionAboveItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(10, 0));
         model.resizeSelection(new Point(11, 1));
         assertSelected();
@@ -88,7 +100,7 @@
     }
 
     public void testSelectionBelowItems() {
-        setUp(5, 4);
+        initData(5, 4);
         model.startSelection(new Point(10, VIEWPORT_HEIGHT - 1));
         model.resizeSelection(new Point(11, VIEWPORT_HEIGHT - 2));
         assertSelected();
@@ -96,7 +108,7 @@
     }
 
     public void testVerticalSelectionBetweenItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(106, 0));
         model.resizeSelection(new Point(107, 200));
         assertSelected();
@@ -104,7 +116,7 @@
     }
 
     public void testHorizontalSelectionBetweenItems() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(0, 105));
         model.resizeSelection(new Point(200, 106));
         assertSelected();
@@ -112,7 +124,7 @@
     }
 
     public void testGrowingAndShrinkingSelection() {
-        setUp(20, 4);
+        initData(20, 4);
         model.startSelection(new Point(0, 0));
         model.resizeSelection(new Point(5, 5));
         assertSelected(0);
@@ -142,7 +154,7 @@
     }
 
     public void testSelectionMovingAroundOrigin() {
-        setUp(16, 4);
+        initData(16, 4);
         model.startSelection(new Point(210, 210));
         model.resizeSelection(new Point(viewWidth - 1, 0));
         assertSelected(2, 3, 6, 7);
@@ -156,7 +168,7 @@
     }
 
     public void testScrollingBandSelect() {
-        setUp(40, 4);
+        initData(40, 4);
         model.startSelection(new Point(0, 0));
         model.resizeSelection(new Point(100, VIEWPORT_HEIGHT - 1));
         assertSelected(0, 4, 8, 12, 16);
@@ -173,14 +185,14 @@
         assertEquals(0, model.getPositionNearestOrigin());
     }
 
-    private static void assertSelected(int... selectedPositions) {
+    private void assertSelected(int... selectedPositions) {
         assertEquals(selectedPositions.length, lastSelection.size());
         for (int position : selectedPositions) {
             assertTrue(lastSelection.contains(Integer.toString(position)));
         }
     }
 
-    private static void scroll(int dy) {
+    private void scroll(int dy) {
         assertTrue(env.verticalOffset + VIEWPORT_HEIGHT + dy <= env.getTotalHeight());
         env.verticalOffset += dy;
         model.onScrolled(null, 0, dy);
@@ -322,30 +334,5 @@
         public void focusItem(int i) {
             throw new UnsupportedOperationException();
         }
-
-        @Override
-        public String getModelIdFromAdapterPosition(int position) {
-            return Integer.toString(position);
-        }
-
-        @Override
-        public int getItemCount() {
-            return mNumChildren;
-        }
-
-        @Override
-        public List<String> getModelIds() {
-            return null;
-        }
-
-        @Override
-        public void notifyItemChanged(String id) {
-            throw new UnsupportedOperationException();
-        }
-
-        @Override
-        public void registerDataObserver(AdapterDataObserver observer) {
-            throw new UnsupportedOperationException();
-        }
     }
 }
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java
new file mode 100644
index 0000000..c8d424f
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContentProvider.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.net.Uri;
+import android.os.Bundle;
+import android.provider.DocumentsContract;
+import android.test.mock.MockContentProvider;
+
+import com.android.documentsui.model.DocumentInfo;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A very simple test double for ContentProvider. Useful in this package only.
+ */
+class TestContentProvider extends MockContentProvider {
+    List<Uri> mDeleted = new ArrayList<>();
+
+    @Override
+    public Bundle call(String method, String arg, Bundle extras) {
+        // Intercept and log delete method calls.
+        if (DocumentsContract.METHOD_DELETE_DOCUMENT.equals(method)) {
+            final Uri documentUri = extras.getParcelable(DocumentsContract.EXTRA_URI);
+            mDeleted.add(documentUri);
+            return new Bundle();
+        } else {
+            return super.call(method, arg, extras);
+        }
+    }
+
+    public void assertWasDeleted(DocumentInfo doc) {
+        ModelTest.assertTrue(mDeleted.contains(doc.derivedUri));
+    }
+}
\ No newline at end of file
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
new file mode 100644
index 0000000..714062d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestContext.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.content.ContentResolver;
+import android.content.Context;
+import android.content.ContextWrapper;
+import android.test.mock.MockContentResolver;
+
+public final class TestContext {
+
+    /**
+     * Returns a Context configured with test provider for authority.
+     */
+    static Context createStorageTestContext(Context context, String authority) {
+        final MockContentResolver testResolver = new MockContentResolver();
+        TestContentProvider provider = new TestContentProvider();
+        testResolver.addProvider(authority, provider);
+
+        return new ContextWrapper(context) {
+            @Override
+            public ContentResolver getContentResolver() {
+                return testResolver;
+            }
+        };
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
new file mode 100644
index 0000000..267f47d
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestDocumentsAdapter.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.util.SparseArray;
+import android.view.ViewGroup;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A skeletal {@link DocumentsAdapter} test double.
+ */
+public class TestDocumentsAdapter extends DocumentsAdapter {
+
+    List<String> mModelIds = new ArrayList<>();
+
+    public TestDocumentsAdapter(List<String> modelIds) {
+        mModelIds = modelIds;
+    }
+
+    @Override
+    public void onModelUpdate(Model model) {
+    }
+
+    @Override
+    public void onModelUpdateFailed(Exception e) {
+    }
+
+    @Override
+    List<String> getModelIds() {
+        return mModelIds;
+    }
+
+    @Override
+    void onItemSelectionChanged(String id) {
+    }
+
+    @Override
+    String getModelId(int position) {
+        return mModelIds.get(position);
+    }
+
+    @Override
+    public SparseArray<String> hide(String... ids) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    void unhide(SparseArray<String> ids) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public DocumentHolder onCreateViewHolder(ViewGroup parent, int viewType) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public void onBindViewHolder(DocumentHolder holder, int position) {
+        throw new UnsupportedOperationException();
+    }
+
+    @Override
+    public int getItemCount() {
+        return mModelIds.size();
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
new file mode 100644
index 0000000..3a537a6
--- /dev/null
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestModel.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.documentsui.dirlist;
+
+import android.content.Context;
+import android.database.MatrixCursor;
+import android.provider.DocumentsContract.Document;
+
+import com.android.documentsui.DirectoryResult;
+import com.android.documentsui.RootCursorWrapper;
+import com.android.documentsui.dirlist.MultiSelectManager.Selection;
+
+import java.util.Random;
+import java.util.Set;
+
+public class TestModel extends Model {
+
+    private static final String[] COLUMNS = new String[]{
+        RootCursorWrapper.COLUMN_AUTHORITY,
+        Document.COLUMN_DOCUMENT_ID,
+        Document.COLUMN_FLAGS,
+        Document.COLUMN_DISPLAY_NAME,
+        Document.COLUMN_SIZE,
+        Document.COLUMN_MIME_TYPE
+    };
+
+    private final String mAuthority;
+    private Set<String> mDeleted;
+
+    /**
+     * Creates a new context. context must be configured with provider for authority.
+     * @see TestContext#createStorageTestContext(Context, String).
+     */
+    public TestModel(Context context, String authority) {
+        super(context);
+        mAuthority = authority;
+    }
+
+    void update(String... names) {
+        Random rand = new Random();
+
+        MatrixCursor c = new MatrixCursor(COLUMNS);
+        for (int i = 0; i < names.length; i++) {
+            MatrixCursor.RowBuilder row = c.newRow();
+            row.add(RootCursorWrapper.COLUMN_AUTHORITY, mAuthority);
+            row.add(Document.COLUMN_DOCUMENT_ID, Integer.toString(i));
+            row.add(Document.COLUMN_FLAGS, Document.FLAG_SUPPORTS_DELETE);
+            // Generate random document names and sizes. This forces the model's internal sort code
+            // to actually do something.
+            row.add(Document.COLUMN_DISPLAY_NAME, names[i]);
+            row.add(Document.COLUMN_SIZE, rand.nextInt());
+        }
+
+        DirectoryResult r = new DirectoryResult();
+        r.cursor = c;
+        update(r);
+    }
+
+    // Note that model id includes authority qualifier and is distinct
+    // WRT documentId because of this.
+    String idForPosition(int p) {
+        return createModelId(mAuthority, Integer.toString(p));
+    }
+
+    @Override
+    public void delete(Selection selected, DeletionListener listener) {
+        for (String id : selected.getAll()) {
+            mDeleted.add(id);
+        }
+        listener.onCompletion();
+    }
+}
diff --git a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
index fc85f2b..c4cfd3a 100644
--- a/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
+++ b/packages/DocumentsUI/tests/src/com/android/documentsui/dirlist/TestSelectionEnvironment.java
@@ -18,7 +18,6 @@
 
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.support.v7.widget.RecyclerView.AdapterDataObserver;
 import android.support.v7.widget.RecyclerView.OnScrollListener;
 import android.view.View;
 
@@ -28,10 +27,7 @@
 
 public class TestSelectionEnvironment implements SelectionEnvironment {
 
-    private List<String> mItems;
-
     public TestSelectionEnvironment(List<String> items) {
-        mItems = items;
     }
 
     @Override
@@ -114,27 +110,4 @@
     @Override
     public void focusItem(int position) {
     }
-
-    @Override
-    public String getModelIdFromAdapterPosition(int position) {
-        return mItems.get(position);
-    }
-
-    @Override
-    public int getItemCount() {
-        return mItems.size();
-    }
-
-    @Override
-    public List<String> getModelIds() {
-        return null;
-    }
-
-    @Override
-    public void notifyItemChanged(String id) {
-    }
-
-    @Override
-    public void registerDataObserver(AdapterDataObserver observer) {
-    }
 }
diff --git a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
index 82fd512..3dc5d7e 100644
--- a/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
+++ b/packages/PrintSpooler/src/com/android/printspooler/model/NotificationController.java
@@ -158,11 +158,14 @@
             builder.addAction(secondAction);
         }
 
-        if (printJob.getState() == PrintJobInfo.STATE_STARTED) {
+        if (printJob.getState() == PrintJobInfo.STATE_STARTED
+                || printJob.getState() == PrintJobInfo.STATE_QUEUED) {
             float progress = printJob.getProgress();
             if (progress >= 0) {
-                builder.setProgress(Integer.MAX_VALUE, (int)(Integer.MAX_VALUE * progress),
+                builder.setProgress(Integer.MAX_VALUE, (int) (Integer.MAX_VALUE * progress),
                         false);
+            } else {
+                builder.setProgress(Integer.MAX_VALUE, 0, true);
             }
         }
 
diff --git a/packages/SettingsLib/res/values-af/strings.xml b/packages/SettingsLib/res/values-af/strings.xml
index 0d9d79c..ebe8752 100644
--- a/packages/SettingsLib/res/values-af/strings.xml
+++ b/packages/SettingsLib/res/values-af/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Laat enige program na ekstern geskryf word, ongeag manifeswaardes"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Verplig verstelbare groottes vir aktiwiteite"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Maak grootte van alle aktiwiteite verstelbaar vir veelvuldige vensters, ongeag manifeswaardes."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Aktiveer vormvrye vensters"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiveer steun vir eksperimentele vormvrye vensters."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Werkskerm-rugsteunwagwoord"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volle rekenaarrugsteune word nie tans beskerm nie"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak om die wagwoord vir volledige rekenaarrugsteune te verander of te verwyder"</string>
diff --git a/packages/SettingsLib/res/values-am/strings.xml b/packages/SettingsLib/res/values-am/strings.xml
index 1c9b0a9..e33d0fa 100644
--- a/packages/SettingsLib/res/values-am/strings.xml
+++ b/packages/SettingsLib/res/values-am/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"አንጸባራቂ እሴቶች ግምት ውስጥ ሳይገቡ ማንኛውም መተግበሪያ ወደ ውጫዊ ማከማቻ ለመጻፍ ብቁ ያደርጋል።"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"እንቅስቃሴዎች ዳግመኛ እንዲመጣጠኑ አስገድድ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"የዝርዝር ሰነድ እሴቶች ምንም ይሁኑ ምን ለበርካታ መስኮቶች ሁሉንም እንቅስቃሴዎች ዳግም የሚመጣጠኑ እንዲሆኑ ያደርጋቸዋል።"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"የነጻ ቅርጽ መስኮቶችን ያንቁ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"የሙከራ ነጻ ቅርጽ መስኮቶች ድጋፍን ያነቃል።"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"የዴስክቶፕ መጠባበቂያ ይለፍ ቃል"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ዴስክቶፕ ሙሉ ምትኬዎች በአሁኑ ሰዓት አልተጠበቁም"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ለዴስክቶፕ ሙሉ ምትኬዎች የይለፍ ቃል ለመለወጥ ወይም ለማስወገድ ንካ"</string>
diff --git a/packages/SettingsLib/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index fc11a6b..71761b9 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"تأهيل أي تطبيق بحيث تتم كتابته على سعة تخزين خارجية، بغض النظر عن قيم البيان"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"فرض إمكانية تغيير على الأنشطة"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"لتمكين تغيير حجم جميع الأنشطة لتناسب تعدد النوافذ، بغض النظر عن قيم البيان."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"تمكين النوافذ الحرة"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"لتمكين إتاحة استخدام النوافذ الحرة التجريبية."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"كلمة مرور احتياطية للكمبيوتر"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"النسخ الاحتياطية الكاملة لسطح المكتب غير محمية في الوقت الحالي"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"المس لتغيير كلمة مرور النسخ الاحتياطية الكاملة لسطح المكتب أو إزالتها"</string>
diff --git a/packages/SettingsLib/res/values-az-rAZ/strings.xml b/packages/SettingsLib/res/values-az-rAZ/strings.xml
index 4a5ea37..b5a7181 100644
--- a/packages/SettingsLib/res/values-az-rAZ/strings.xml
+++ b/packages/SettingsLib/res/values-az-rAZ/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Seçilmiş hər hansı tətbiqi bəyannamə dəyərlərindən aslı olmayaraq xarici yaddaşa yazılabilən edir."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Ölçü dəyişdirmək üçün məcburi fəaliyyətlər"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bəyannamə dəyərlərindən aslı olmayaraq bütün fəaliyyətləri çoxsaylı pəncərə üçün dəyişkən ölçülü edir."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Freeform windows aktiv edin"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Sınaq üçün freeform windows aktiv edir"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü rezerv parolu"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam rezervlər hazırda qorunmayıblar."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstünün tam rezevr kopyalanması üçün parolu dəyişmək və ya silmək üçün toxunun"</string>
diff --git a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
index 676c618..54d2dfa 100644
--- a/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
+++ b/packages/SettingsLib/res/values-b+sr+Latn/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Omogućava upisivanje svih aplikacija u spoljnu memoriju, bez obzira na vrednosti manifesta"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Prinudno omogući promenu veličine aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Omogućava promenu veličine svih aktivnosti za režim sa više prozora, bez obzira na vrednosti manifesta."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Lozinka rezervne kopije za računar"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervne kopije čitavog sistema trenutno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dodirnite da biste promenili ili uklonili lozinku za pravljenje rezervnih kopija čitavog sistema na računaru"</string>
diff --git a/packages/SettingsLib/res/values-bg/strings.xml b/packages/SettingsLib/res/values-bg/strings.xml
index 8180261..95badc5 100644
--- a/packages/SettingsLib/res/values-bg/strings.xml
+++ b/packages/SettingsLib/res/values-bg/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Позволява прилож. да се записват във външ. хранил. независимо от стойностите в манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Възможност за преоразмеряване на активностите"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Дава възможност за преоразмеряване на всички активности в режима за няколко прозореца независимо от стойностите в манифеста."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Наст. комп.: Парола"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Понастоящем пълните резервни копия за настолен компютър не са защитени"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Докоснете, за да промените или премахнете паролата за пълни резервни копия на настолния компютър"</string>
diff --git a/packages/SettingsLib/res/values-bn-rBD/strings.xml b/packages/SettingsLib/res/values-bn-rBD/strings.xml
index a5787f5..e4d97d7 100644
--- a/packages/SettingsLib/res/values-bn-rBD/strings.xml
+++ b/packages/SettingsLib/res/values-bn-rBD/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ম্যানিফেস্ট মানগুলি নির্বিশেষে যেকোনো অ্যাপ্লিকেশানকে বাহ্যিক সঞ্চয়স্থানে লেখার উপযুক্ত বানায়"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"আকার পরিবর্তনযোগ্য করার জন্য ক্রিয়াকলাপগুলিকে জোর করুন"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ম্যানিফেস্ট মানগুলির নির্বিশেষে মাল্টি-উইন্ডোর জন্য সমস্ত ক্রিয়াকলাপগুলিকে আকার পরিবর্তনযোগ্য করে তোলে৷"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"ডেস্কটপ ব্যাকআপ পাসওয়ার্ড"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ডেস্কটপ পূর্ণ ব্যাকআপ বর্তমানে সুরক্ষিত নয়"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ডেস্কটপ পুরো ব্যাকআপের জন্য পাসওয়ার্ড পরিবর্তন বা মুছে ফেলার জন্য স্পর্শ করুন"</string>
diff --git a/packages/SettingsLib/res/values-ca/strings.xml b/packages/SettingsLib/res/values-ca/strings.xml
index 8553ed9..93b6438 100644
--- a/packages/SettingsLib/res/values-ca/strings.xml
+++ b/packages/SettingsLib/res/values-ca/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet que les aplicacions es puguin escriure en un dispositiu d’emmagatzematge extern, independentment dels valors definits"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Força l\'ajust de la mida de les activitats"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet ajustar la mida de totes les activitats per al mode multifinestra, independentment dels valors definits."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasenya per a còpies d\'ordinador"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les còpies de seguretat d\'ordinador completes no estan protegides"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca per canviar o eliminar la contrasenya per a còpies de seguretat d\'ordinador completes"</string>
diff --git a/packages/SettingsLib/res/values-cs/strings.xml b/packages/SettingsLib/res/values-cs/strings.xml
index 495f10f..beb8f94 100644
--- a/packages/SettingsLib/res/values-cs/strings.xml
+++ b/packages/SettingsLib/res/values-cs/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Každou aplikaci bude možné zapsat do externího úložiště, bez ohledu na hodnoty manifestu"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Vynutit možnost změny velikosti aktivit"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Velikost všech aktivit bude možné změnit na několik oken (bez ohledu na hodnoty manifestu)."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivovat okna s volným tvarem"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivuje podporu experimentálních oken s volným tvarem."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pro zálohy v počítači"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy v počítači nejsou v současné době chráněny"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tuto možnost vyberte, chcete-li změnit nebo odebrat heslo pro úplné zálohy v počítači"</string>
diff --git a/packages/SettingsLib/res/values-da/strings.xml b/packages/SettingsLib/res/values-da/strings.xml
index 82654bc..3923dbd 100644
--- a/packages/SettingsLib/res/values-da/strings.xml
+++ b/packages/SettingsLib/res/values-da/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gør det muligt at overføre enhver app til et eksternt lager uafhængigt af manifestværdier"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til at kunne tilpasses"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Sørger for, at alle aktiviteter kan tilpasses flere vinduer uafhængigt af manifestværdier."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivér vinduer i frit format"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktiverer understøttelse af eksperimentelle vinduer i frit format."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Kode til lokal sikkerhedskopi"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Lokale fuldstændige sikkerhedskopieringer er i øjeblikket ikke beskyttet"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryk for at skifte eller fjerne adgangskoden til fuld lokal sikkerhedskopiering"</string>
diff --git a/packages/SettingsLib/res/values-de/strings.xml b/packages/SettingsLib/res/values-de/strings.xml
index a2f750b..0b1238b 100644
--- a/packages/SettingsLib/res/values-de/strings.xml
+++ b/packages/SettingsLib/res/values-de/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ermöglicht es jeder qualifizierten App, Daten auf externen Speicher zu schreiben, unabhängig von den Manifestwerten"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Anpassen der Größe von Aktivitäten erzwingen"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ermöglicht es, die Größe aller Aktivitäten an den Mehrfenstermodus anzupassen, unabhängig von den Manifestwerten."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop-Sicherungspasswort"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Vollständige Desktop-Sicherungen sind momentan nicht passwortgeschützt."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Zum Ändern oder Entfernen des Passworts für vollständige Desktop-Sicherungen berühren"</string>
diff --git a/packages/SettingsLib/res/values-el/strings.xml b/packages/SettingsLib/res/values-el/strings.xml
index d426616..c3acca7 100644
--- a/packages/SettingsLib/res/values-el/strings.xml
+++ b/packages/SettingsLib/res/values-el/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Κάνει κάθε εφαρμογή κατάλληλη για εγγραφή σε εξωτερικό χώρο αποθήκευσης, ανεξάρτητα από τις τιμές του μανιφέστου"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Αναγκαστική δυνατότητα αλλαγής μεγέθους δραστηριοτήτων"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Να έχουν όλες οι δραστηριότητες δυνατότητα αλλαγής μεγέθους για την προβολή πολλαπλών παραθύρων, ανεξάρτητα από τις τιμές του μανιφέστου."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Ενεργοποίηση παραθύρων ελεύθερης μορφής"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ενεργοποιεί την υποστήριξη για πειραματικά παράθυρα ελεύθερης μορφής."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Εφ/κός κωδικός desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας δεν προστατεύονται αυτήν τη στιγμή"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Αγγίξτε για αλλαγή ή κατάργηση του κωδικού πρόσβασης για τα πλήρη αντίγραφα ασφαλείας επιφάνειας εργασίας"</string>
diff --git a/packages/SettingsLib/res/values-en-rAU/strings.xml b/packages/SettingsLib/res/values-en-rAU/strings.xml
index b8c8521..dae40d9 100644
--- a/packages/SettingsLib/res/values-en-rAU/strings.xml
+++ b/packages/SettingsLib/res/values-en-rAU/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rGB/strings.xml b/packages/SettingsLib/res/values-en-rGB/strings.xml
index b8c8521..dae40d9 100644
--- a/packages/SettingsLib/res/values-en-rGB/strings.xml
+++ b/packages/SettingsLib/res/values-en-rGB/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-en-rIN/strings.xml b/packages/SettingsLib/res/values-en-rIN/strings.xml
index b8c8521..dae40d9 100644
--- a/packages/SettingsLib/res/values-en-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-en-rIN/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Makes any app eligible to be written to external storage, regardless of manifest values"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Force activities to be re-sizable"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Makes all activities re-sizable for multi-window, regardless of manifest values."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop backup password"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Desktop full backups aren\'t currently protected"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Touch to change or remove the password for desktop full backups"</string>
diff --git a/packages/SettingsLib/res/values-es-rUS/strings.xml b/packages/SettingsLib/res/values-es-rUS/strings.xml
index 34ebef4..855b72c 100644
--- a/packages/SettingsLib/res/values-es-rUS/strings.xml
+++ b/packages/SettingsLib/res/values-es-rUS/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Cualquier aplicación puede escribirse en una memoria externa, independientemente de los valores del manifiesto."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar actividades para que cambien de tamaño"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que todas las actividades puedan cambiar de tamaño para el modo multiventana, sin importar los valores del manifiesto."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contraseñas"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tus copias de seguridad de escritorio no están protegidas por contraseña."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar o eliminar la contraseña de las copias de seguridad completas de tu escritorio."</string>
diff --git a/packages/SettingsLib/res/values-es/strings.xml b/packages/SettingsLib/res/values-es/strings.xml
index cedd582..858c1b6 100644
--- a/packages/SettingsLib/res/values-es/strings.xml
+++ b/packages/SettingsLib/res/values-es/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hace que cualquier aplicación se pueda escribir en un dispositivo de almacenamiento externo, independientemente de los valores definidos"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar el ajuste de tamaño de las actividades"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite que se pueda ajustar el tamaño de todas las actividades para el modo multiventana, independientemente de los valores establecidos."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Habilitar ventanas de forma libre"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Permite utilizar ventanas de forma libre experimentales."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contraseña para copias de ordenador"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Las copias de seguridad completas de ordenador no están protegidas"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocar para cambiar o quitar la contraseña para las copias de seguridad completas de ordenador"</string>
diff --git a/packages/SettingsLib/res/values-et-rEE/strings.xml b/packages/SettingsLib/res/values-et-rEE/strings.xml
index 714004e..7f1056c 100644
--- a/packages/SettingsLib/res/values-et-rEE/strings.xml
+++ b/packages/SettingsLib/res/values-et-rEE/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lubab rakendusi kirjutada välisesse salvestusruumi olenemata manifesti väärtustest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Muuda tegevuste suurused muudetavaks"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Muudab kõigi tegevuste suurused mitme aknaga vaates olenemata manifesti väärtustest muudetavaks."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Luba vabas vormis aknad"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Lubatakse katseliste vabas vormis akende tugi."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Arvutivarunduse parool"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Täielikud arvutivarundused pole praegu kaitstud"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Puudutage, et muuta või eemaldada täielike arvutivarunduste parool"</string>
diff --git a/packages/SettingsLib/res/values-eu-rES/strings.xml b/packages/SettingsLib/res/values-eu-rES/strings.xml
index 7f47bf3..fe5fc29 100644
--- a/packages/SettingsLib/res/values-eu-rES/strings.xml
+++ b/packages/SettingsLib/res/values-eu-rES/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikazioek kanpoko memorian idatz dezakete, manifestuaren balioak kontuan izan gabe"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Behartu jardueren tamaina doitu ahal izatea"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifestuan jartzen duena jartzen duela ere, jarduera guztien tamaina doitzeko aukera ematen du, hainbat leihotan erabili ahal izan daitezen."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Tokiko babeskop. pasahitza"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Une honetan, ordenagailuko babeskopia osoak ez daude babestuta."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ukitu ordenagailuko babeskopia osoak egiteko pasahitza aldatzeko edo kentzeko"</string>
diff --git a/packages/SettingsLib/res/values-fa/strings.xml b/packages/SettingsLib/res/values-fa/strings.xml
index 1f8b575..e1a35f7 100644
--- a/packages/SettingsLib/res/values-fa/strings.xml
+++ b/packages/SettingsLib/res/values-fa/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"بدون توجه به مقادیر مانیفست، هر برنامه‌ای را برای نوشتن در حافظه خارجی واجد شرایط می‌کند"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"اجبار فعالیت‌ها به قابل تغییر اندازه بودن"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"بدون درنظر گرفتن مقادیر مانیفست، همه فعالیت‌ها را برای چندپنجره قابل تغییر اندازه می‌کند."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"گذرواژه پشتیبان‌گیری محلی"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"پشتیبان‌گیری کامل رایانه درحال حاضر محافظت نمی‌شود"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"برای تغییر یا حذف گذرواژه برای نسخه‌های پشتیبان کامل دسک‌تاپ لمس کنید"</string>
diff --git a/packages/SettingsLib/res/values-fi/strings.xml b/packages/SettingsLib/res/values-fi/strings.xml
index e4b4b93..498f204 100644
--- a/packages/SettingsLib/res/values-fi/strings.xml
+++ b/packages/SettingsLib/res/values-fi/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mahdollistaa sovellusten tallentamisen ulkoiseen tall.tilaan luettelosta riippumatta"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Pakota kaikki toiminnot hyväksymään koon muutos"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pakottaa kaikki toiminnot hyväksymään koon muuttamisen rinnakkaisnäkymään luettelon arvoista riippumatta."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Varmuuskop. salasana"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Tietokoneen kaikkien tietojen varmuuskopiointia ei ole tällä hetkellä suojattu"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Muuta tai vaihda tietokoneen kaikkien tietojen varmuuskopioinnin salasana koskettamalla"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 66c54a1..b32bfb7 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Permet enreg. d\'applis sur espace stockage externe"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer les activités à être redimensionnables"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index e56940a..0190454 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rend possible enregistrement de toute appli sur espace stockage externe, indépendamment valeurs fichier manifeste."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forcer possibilité de redimensionner les activités"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Mot de passe sauvegarde PC"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Les sauvegardes complètes sur PC ne sont pas protégées actuellement."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Appuyez pour modifier ou supprimer le mot de passe utilisé pour les sauvegardes complètes sur PC."</string>
diff --git a/packages/SettingsLib/res/values-gl-rES/strings.xml b/packages/SettingsLib/res/values-gl-rES/strings.xml
index 9bcf770..0efe805 100644
--- a/packages/SettingsLib/res/values-gl-rES/strings.xml
+++ b/packages/SettingsLib/res/values-gl-rES/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Fai que calquera aplicación se poida escribir nun almacenamento externo, independentemente dos valores expresados"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forzar o axuste do tamaño das actividades"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite axustar o tamaño de todas as actividades para o modo de varias ventás, independentemente dos valores definidos."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Activar ventás de forma libre"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Activa a compatibilidade con ventás de forma libre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Contrasinal para copias"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"As copias de seguridade de ordenador completas non están protexidas"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toca para cambiar ou eliminar o contrasinal para as copias de seguranza completas do escritorio"</string>
diff --git a/packages/SettingsLib/res/values-gu-rIN/strings.xml b/packages/SettingsLib/res/values-gu-rIN/strings.xml
index 6dff8fa..4b72648 100644
--- a/packages/SettingsLib/res/values-gu-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-gu-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"મેનિફેસ્ટ મૂલ્યોને ધ્યાનમાં લીધા સિવાય, કોઈપણ એપ્લિકેશનને બાહ્ય સ્ટોરેજ પર લખાવા માટે લાયક બનાવે છે"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"પ્રવૃત્તિઓને ફરીથી કદ યોગ્ય થવા માટે ફરજ પાડો"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"તમામ પ્રવૃત્તિઓને મલ્ટી-વિંડો માટે ફરીથી કદ બદલી શકે તેવી બનાવે છે, મેનીફેસ્ટ મુલ્યોને ધ્યાનમાં લીધા સિવાય."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"મુક્તાકાર વિંડોઝ સક્ષમ કરો"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"પ્રાયોગિક મુક્તાકાર વિંડોઝ માટે સમર્થનને સક્ષમ કરે છે."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"ડેસ્કટૉપ બેકઅપ પાસવર્ડ"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ હાલમાં સુરક્ષિત નથી"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ડેસ્કટૉપ સંપૂર્ણ બેકઅપ્સ માટેનો પાસવર્ડ બદલવા અથવા દૂર કરવા માટે ટચ કરો"</string>
diff --git a/packages/SettingsLib/res/values-hi/strings.xml b/packages/SettingsLib/res/values-hi/strings.xml
index 9ce83fa..5224c38 100644
--- a/packages/SettingsLib/res/values-hi/strings.xml
+++ b/packages/SettingsLib/res/values-hi/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"इससे कोई भी ऐप मेनिफेस्‍ट मान अनदेखा करके, बाहरी मेमोरी पर लिखने योग्‍य बन जाता है"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"आकार बदले जाने के लिए गतिविधियों को बाध्य करें"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"एकाधिक-विंडो के लिए सभी गतिविधियों के आकार को बदले जाने योग्य बनाता है, चाहे मेनिफेस्ट मान कुछ भी हों."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"फ़्रीफ़ॉर्म विंडो सक्षम करें"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ़्रीफ़ॉर्म विंडो का समर्थन सक्षम करती है."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्‍कटॉप बैकअप पासवर्ड"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्‍कटॉप पूर्ण बैकअप वर्तमान में सुरक्षित नहीं हैं"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटॉप के पूर्ण बैकअप के पासवर्ड को बदलने या निकालने के लिए स्‍पर्श करें."</string>
diff --git a/packages/SettingsLib/res/values-hr/strings.xml b/packages/SettingsLib/res/values-hr/strings.xml
index dd02171..5cde233 100644
--- a/packages/SettingsLib/res/values-hr/strings.xml
+++ b/packages/SettingsLib/res/values-hr/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Aplikacije se mogu zapisivati u vanjsku pohranu neovisno o manifestu"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Nametni mogućnost promjene veličine za aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veličina svih aktivnosti može se mijenjati za više prozora, neovisno o vrijednostima manifesta."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Zaporka sigurnosne kopije"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Potpune sigurnosne kopije na stolnom računalu trenutačno nisu zaštićene"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Odaberite za promjenu ili uklanjanje zaporke u potpunim sigurnosnim kopijama na stolnom računalu"</string>
diff --git a/packages/SettingsLib/res/values-hu/strings.xml b/packages/SettingsLib/res/values-hu/strings.xml
index 9b3a386..3559f1e 100644
--- a/packages/SettingsLib/res/values-hu/strings.xml
+++ b/packages/SettingsLib/res/values-hu/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Lehetővé teszi, hogy külső tárhelyre lehessen írni"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tevékenységek átméretezésének kényszerítése"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Lehetővé teszi, hogy az összes tevékenység átméretezhető legyen a többablakos megjelenítés érdekében a jegyzékértékektől függetlenül."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Szabad formájú ablakok engedélyezése"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Engedélyezi a kísérleti jellegű, szabad formájú ablakok támogatását."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Asztali mentés jelszava"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Az asztali teljes biztonsági mentések jelenleg nem védettek."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Érintse meg, ha módosítaná vagy eltávolítaná a jelszót az asztali teljes mentésekhez"</string>
diff --git a/packages/SettingsLib/res/values-hy-rAM/strings.xml b/packages/SettingsLib/res/values-hy-rAM/strings.xml
index 27db9fe..42c9a05 100644
--- a/packages/SettingsLib/res/values-hy-rAM/strings.xml
+++ b/packages/SettingsLib/res/values-hy-rAM/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Թույլ է տալիս պահել հավելվածը արտաքին սարքում՝ մանիֆեստի արժեքներից անկախ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Ստիպել, որ ակտիվությունների չափերը լինեն փոփոխելի"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Բոլոր ակտիվությունների չափերը բազմապատուհան ռեժիմի համար դարձնել փոփոխելի՝ մանիֆեստի արժեքներից անկախ:"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Աշխատասեղանի պահուստավորման գաղտնաբառ"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Աշխատասեղանի ամբողջական պահուստավորումները այժմ պաշտպանված չեն"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Աշխատասեղանի ամբողջական պահուստավորման համար ընտրել փոխել կամ հեռացնել գաղտնաբառը"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index 0cea206..6988a73 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Membuat semua aplikasi dapat ditulis ke penyimpanan eksterna"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktivitas agar ukurannya dapat diubah"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Membuat semua aktivitas dapat diubah ukurannya untuk banyak jendela, terlepas dari nilai manifes."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Sandi cadangan desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Saat ini cadangan desktop penuh tidak dilindungi"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh guna mengubah atau menghapus sandi untuk cadangan lengkap desktop"</string>
diff --git a/packages/SettingsLib/res/values-is-rIS/strings.xml b/packages/SettingsLib/res/values-is-rIS/strings.xml
index b3509ca..8d912e9 100644
--- a/packages/SettingsLib/res/values-is-rIS/strings.xml
+++ b/packages/SettingsLib/res/values-is-rIS/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gerir hvaða forriti sem er kleift að skrifa í ytri geymslu, burtséð frá gildum í upplýsingaskrá"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Þvinga breytanlega stærð virkni"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gerir stærð allrar virkni breytanlega svo að hún henti fyrir marga glugga, óháð gildum í upplýsingaskrá."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Aðgangsorð tölvuafritunar"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Heildarafritun á tölvu er ekki varin sem stendur."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Snertu til að breyta eða fjarlægja aðgangsorðið fyrir heildarafritun á tölvu"</string>
diff --git a/packages/SettingsLib/res/values-it/strings.xml b/packages/SettingsLib/res/values-it/strings.xml
index 9f897f7..2d98a74 100644
--- a/packages/SettingsLib/res/values-it/strings.xml
+++ b/packages/SettingsLib/res/values-it/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Rende l\'app idonea all\'installaz. su mem. esterna, senza considerare i valori manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Imponi formato modificabile alle attività"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Rende il formato di tutte le attività modificabile per la modalità multi-finestra, indipendentemente dai valori manifest."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Attiva finestre a forma libera"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Attiva il supporto per le finestre a forma libera sperimentali."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Password di backup desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"I backup desktop completi non sono attualmente protetti."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tocca per modificare o rimuovere la password per i backup desktop completi"</string>
diff --git a/packages/SettingsLib/res/values-iw/strings.xml b/packages/SettingsLib/res/values-iw/strings.xml
index 2d44612..e175208 100644
--- a/packages/SettingsLib/res/values-iw/strings.xml
+++ b/packages/SettingsLib/res/values-iw/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"מאפשר כתיבה של כל אפליקציה באחסון חיצוני, ללא התחשבות בערכי המניפסט"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"אלץ יכולת קביעת גודל של הפעילויות"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"מאפשר יכולת קביעת גודל של כל הפעילויות לריבוי חלונות, ללא קשר לערך המניפסט."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"סיסמת גיבוי מקומי"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"גיבויים מלאים בשולחן העבודה אינם מוגנים כעת"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"גע כדי לשנות או להסיר את הסיסמה עבור גיבויים מלאים בשולחן העבודה"</string>
diff --git a/packages/SettingsLib/res/values-ja/strings.xml b/packages/SettingsLib/res/values-ja/strings.xml
index 81a5eaf..bf9bf8a 100644
--- a/packages/SettingsLib/res/values-ja/strings.xml
+++ b/packages/SettingsLib/res/values-ja/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"マニフェストの値に関係なく、すべてのアプリを外部ストレージに書き込めるようになります"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"アクティビティをサイズ変更可能にする"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"マニフェストの値に関係なく、マルチウィンドウですべてのアクティビティのサイズを変更できるようになります。"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"PCバックアップパスワード"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"デスクトップのフルバックアップは現在保護されていません"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"デスクトップのフルバックアップ用のパスワードを変更または削除する場合にタップします"</string>
@@ -263,9 +267,9 @@
     <item msgid="8280754435979370728">"目に自然な色"</item>
     <item msgid="5363960654009010371">"デジタルコンテンツに最適な色"</item>
   </string-array>
-    <string name="inactive_apps_title" msgid="1317817863508274533">"無効なアプリ"</string>
-    <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"無効。タップすると切り替わります。"</string>
-    <string name="inactive_app_active_summary" msgid="4512911571954375968">"有効。タップすると切り替わります。"</string>
+    <string name="inactive_apps_title" msgid="1317817863508274533">"休止中のアプリ"</string>
+    <string name="inactive_app_inactive_summary" msgid="6768756967594202411">"休止中。タップすると切り替わります。"</string>
+    <string name="inactive_app_active_summary" msgid="4512911571954375968">"実行中。タップすると切り替わります。"</string>
     <string name="runningservices_settings_title" msgid="8097287939865165213">"実行中のサービス"</string>
     <string name="runningservices_settings_summary" msgid="854608995821032748">"現在実行中のサービスを表示して制御する"</string>
     <string name="night_mode_title" msgid="2594133148531256513">"夜間モード"</string>
diff --git a/packages/SettingsLib/res/values-ka-rGE/strings.xml b/packages/SettingsLib/res/values-ka-rGE/strings.xml
index e2dfd7e..da9d204 100644
--- a/packages/SettingsLib/res/values-ka-rGE/strings.xml
+++ b/packages/SettingsLib/res/values-ka-rGE/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"აპები ჩაიწერ. გარე მეხს.-ზე აღწ. ფაილის მნიშვნ. მიუხედ."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ზომაცვლადი აქტივობების იძულება"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"მანიფესტის მნიშვნელობების მიუხედავად, ყველა აქტივობას მრავალი ფანჯრის რეჟიმისთვის ზომაცვლადად აქცევს."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"დესკტოპის სარეზერვო ასლის პაროლი"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"დესკტოპის სრული სარეზერვო ასლები ამჟამად დაცული არ არის"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"შეეხეთ დესკტოპის სრული სარეზერვო ასლების პაროლის შესაცვლელად ან წასაშლელად"</string>
diff --git a/packages/SettingsLib/res/values-kk-rKZ/strings.xml b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
index 1b8e176..549711c 100644
--- a/packages/SettingsLib/res/values-kk-rKZ/strings.xml
+++ b/packages/SettingsLib/res/values-kk-rKZ/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест мәндеріне қарамастан кез келген қолданбаны сыртқы жадқа жазуға жарамды етеді"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Әрекеттерді өлшемін өзгертуге болатын етуге мәжбүрлеу"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест мәндеріне қарамастан барлық әрекеттерді бірнеше терезе үшін өлшемін өзгертуге болатын етеді."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Компьютер үстелінің сақтық көшірмесі"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Жұмыс үстелінің сақтық көшірмелері қазір қорғалмаған"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Жұмыс үстелінің толық сақтық көшірмесінің кілтсөзін өзгерту немесе жою үшін түртіңіз"</string>
diff --git a/packages/SettingsLib/res/values-km-rKH/strings.xml b/packages/SettingsLib/res/values-km-rKH/strings.xml
index 0186a68..aed4365 100644
--- a/packages/SettingsLib/res/values-km-rKH/strings.xml
+++ b/packages/SettingsLib/res/values-km-rKH/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ធ្វើឲ្យកម្មវិធីទាំងឡាយមានសិទ្ធិសរសេរទៅកាន់ឧបករណ៍ផ្ទុកខាងក្រៅ ដោយមិនគិតពីតម្លៃជាក់លាក់"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"បង្ខំឲ្យសកម្មភាពអាចប្តូរទំហំបាន"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"កំណត់ឲ្យសកម្មភាពទាំងអស់អាចប្តូរទំហំបានសម្រាប់ពហុផ្ទាំងវិនដូ ដោយមិនគិតពីតម្លៃមេនីហ្វេសឡើយ។"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"ពាក្យ​សម្ងាត់​បម្រុង​ទុក​លើ​ផ្ទៃតុ"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ការ​បម្រុង​ទុក​ពេញលេញ​លើ​ផ្ទៃតុ​បច្ចុប្បន្ន​មិន​ត្រូវ​បាន​ការពារ​ទេ។"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ប៉ះ ដើម្បី​ប្ដូរ ឬ​លុប​ពាក្យ​សម្ងាត់​សម្រាប់​ការ​បម្រុងទុក​ពេញលេញ​លើ​ផ្ទៃតុ"</string>
diff --git a/packages/SettingsLib/res/values-kn-rIN/strings.xml b/packages/SettingsLib/res/values-kn-rIN/strings.xml
index 56f4006..50e5955 100644
--- a/packages/SettingsLib/res/values-kn-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-kn-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಯಾವುದೇ ಅಪ್ಲಿಕೇಶನ್‌ಗೆ ಬಾಹ್ಯ ಸಂಗ್ರಹಣೆಗೆ ಬರೆಯಲು ಅರ್ಹಗೊಳಿಸುತ್ತದೆ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಒತ್ತಾಯ ಮಾಡಿ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ಮ್ಯಾನಿಫೆಸ್ಟ್ ಮೌಲ್ಯಗಳನ್ನು ಪರಿಗಣಿಸದೇ, ಬಹು-ವಿಂಡೊಗೆ ಎಲ್ಲಾ ಚಟುವಟಿಕೆಗಳನ್ನು ಮರುಗಾತ್ರಗೊಳಿಸುವಂತೆ ಮಾಡುತ್ತದೆ."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳನ್ನು ಸಕ್ರಿಯಗೊಳಿಸಿ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ಪ್ರಾಯೋಗಿಕ ಮುಕ್ತಸ್ವರೂಪದ ವಿಂಡೊಗಳಿಗೆ ಬೆಂಬಲವನ್ನು ಸಕ್ರಿಯಗೊಳಿಸುತ್ತದೆ."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"ಡೆಸ್ಕ್‌ಟಾಪ್ ಬ್ಯಾಕಪ್ ಪಾಸ್‌ವರ್ಡ್"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ಡೆಸ್ಕ್‌ಟಾಪ್‌‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌‌ಗಳನ್ನು ಪ್ರಸ್ತುತ ರಕ್ಷಿಸಲಾಗಿಲ್ಲ"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ಡೆಸ್ಕ್‌ಟಾಪ್‌ನ ಪೂರ್ಣ ಬ್ಯಾಕಪ್‌ಗಳಿಗೆ ಪಾಸ್‌ವರ್ಡ್‌ ಅನ್ನು ಬದಲಾಯಿಸಲು ಅಥವಾ ತೆಗೆದುಹಾಕಲು ಸ್ಪರ್ಶಿಸಿ"</string>
diff --git a/packages/SettingsLib/res/values-ko/strings.xml b/packages/SettingsLib/res/values-ko/strings.xml
index 6ad3efd..ea5dc00 100644
--- a/packages/SettingsLib/res/values-ko/strings.xml
+++ b/packages/SettingsLib/res/values-ko/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"매니페스트 값에 관계없이 앱을 외부 저장소에 작성"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"활동의 크기가 조정 가능하도록 설정"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"모든 활동을 매니페스트 값에 관계없이 멀티 윈도우용으로 크기 조정 가능하도록 설정"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"데스크톱 백업 비밀번호"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"데스크톱 전체 백업에 비밀번호가 설정되어 있지 않음"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"데스크톱 전체 백업에 대한 비밀번호를 변경하거나 삭제하려면 터치하세요."</string>
diff --git a/packages/SettingsLib/res/values-ky-rKG/strings.xml b/packages/SettingsLib/res/values-ky-rKG/strings.xml
index bf37ac4..6a47406 100644
--- a/packages/SettingsLib/res/values-ky-rKG/strings.xml
+++ b/packages/SettingsLib/res/values-ky-rKG/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест маанилерине карабастан бардык колдонмолорду тышкы сактагычка сактоого уруксат берет"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Аракеттердин өлчөмүн өзгөртүүнү мажбурлоо"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Манифест маанилерине карабастан бардык аракеттерди мульти-терезеге өлчөмү өзгөртүлгүдөй кылат."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Компүтердеги бэкаптын сырсөзү"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Компүтердеги толук бэкап учурда корголгон эмес"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Тийип, компүтердеги толук бэкаптын сырсөзүн өзгөртүңүз же жок кылыңыз"</string>
diff --git a/packages/SettingsLib/res/values-lo-rLA/strings.xml b/packages/SettingsLib/res/values-lo-rLA/strings.xml
index 9e6a4b7..538a38c 100644
--- a/packages/SettingsLib/res/values-lo-rLA/strings.xml
+++ b/packages/SettingsLib/res/values-lo-rLA/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ເຮັດ​ໃຫ້ທຸກແອັບ​ມີ​ສິດ​ໄດ້ຮັບການຂຽນ​ໃສ່​ບ່ອນ​ຈັດ​ເກັບ​ພາຍນອກ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ບັງ​ຄັງ​ໃຫ້​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ເຮັດ​ໃຫ້​ທຸກ​ກິດ​ຈະ​ກຳ​ປ່ຽນ​ຂະ​ໜາດ​ໄດ້​ສຳ​ລັບ​ຫຼາຍ​ໜ້າ​ຕ່າງ, ໂດຍ​ບໍ່​ຄຳ​ນຶງ​ເຖິງ​ຄ່າ​ທີ່​ຈະ​ແຈ້ງ."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"ລະຫັດຜ່ານການສຳຮອງຂໍ້ມູນເດັກສະທັອບ"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ການ​ສຳຮອງ​ຂໍ້ມູນ​ເຕັມຮູບແບບ​ໃນ​ເດັກສະທັອບ​ຍັງ​ບໍ່​ໄດ້​ຮັບ​ການ​ປ້ອງກັນ​ໃນ​ເວລາ​ນີ້"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ແຕະເພື່ອປ່ຽນ ຫຼືລຶບລະຫັດຂອງການສຳຮອງຂໍ້ມູນເຕັມຮູບແບບໃນເດັກສະທັອບ"</string>
diff --git a/packages/SettingsLib/res/values-lt/strings.xml b/packages/SettingsLib/res/values-lt/strings.xml
index 2019646..014a6fb 100644
--- a/packages/SettingsLib/res/values-lt/strings.xml
+++ b/packages/SettingsLib/res/values-lt/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Vis. pr. gal. įr. į vid. saug. nepais. apr. vert."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Priv. nust., kad veiksm. b. g. atl. kelių d. lang."</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Nustatoma, kad visus veiksmus būtų galima atlikti kelių dydžių languose, nepaisant aprašo verčių."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Viet. atsrg. kop. slapt."</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Šiuo metu visos vietinės atsarginės kopijos neapsaugotos"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Jei norite pakeisti ar pašalinti visų vietinių atsarginių kopijų slaptažodį, palieskite"</string>
diff --git a/packages/SettingsLib/res/values-lv/strings.xml b/packages/SettingsLib/res/values-lv/strings.xml
index 2f9a83b..87da105 100644
--- a/packages/SettingsLib/res/values-lv/strings.xml
+++ b/packages/SettingsLib/res/values-lv/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Ļauj jebkuru lietotni ierakstīt ārējā krātuvē neatkarīgi no manifesta vērtības."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Pielāgot darbības"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Pielāgo visas darbības vairāku logu režīmam neatkarīgi no vērtībām manifestā."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Datora dublējuma parole"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Darbvirsmas pilnie dublējumi pašlaik nav aizsargāti."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pieskarieties, lai mainītu vai noņemtu paroli pilniem darbvirsmas dublējumiem."</string>
diff --git a/packages/SettingsLib/res/values-mk-rMK/strings.xml b/packages/SettingsLib/res/values-mk-rMK/strings.xml
index 51c2568..b588c2c 100644
--- a/packages/SettingsLib/res/values-mk-rMK/strings.xml
+++ b/packages/SettingsLib/res/values-mk-rMK/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Запишува апл. во надв.меморија, незав. од манифест"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Принуди ги активностите да ја менуваат големината"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Ги прави сите активности да бидат со променлива големина за мултипрозорец, без разлика на вредностите на манифестот."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Овозможи прозорци со слободна форма"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Овозможува поддршка за експериментални прозорци со слободна форма."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Резервна лозинка за работна површина"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Целосни резервни копии на работната површина кои во моментов не се заштитени"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Допрете за да се промени или отстрани лозинката за целосна резервна копија на работната површина"</string>
diff --git a/packages/SettingsLib/res/values-ml-rIN/strings.xml b/packages/SettingsLib/res/values-ml-rIN/strings.xml
index f00103f..d76e87f 100644
--- a/packages/SettingsLib/res/values-ml-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ml-rIN/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, ബാഹ്യ സ്റ്റോറേജിലേക്ക് എഴുതപ്പെടുന്നതിന് ഏതൊരു ആപ്പിനെയും യോഗ്യമാക്കുന്നു"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"വലിപ്പം മാറ്റാൻ പ്രവർത്തനങ്ങളെ നിർബന്ധിക്കുക"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"മാനിഫെസ്റ്റ് മൂല്യങ്ങൾ പരിഗണിക്കാതെ, എല്ലാ പ്രവർത്തനങ്ങളെയും മൾട്ടി-വിൻഡോയ്ക്കായി വലിപ്പം മാറ്റുന്നു."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"ഡെ‌സ്‌ക്ടോപ്പ് ബാക്കപ്പ് പാസ്‌വേഡ്"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾ നിലവിൽ പരിരക്ഷിച്ചിട്ടില്ല"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ഡെസ്‌ക്‌ടോപ്പ് പൂർണ്ണ ബാക്കപ്പുകൾക്കായി പാസ്‌വേഡുകൾ മാറ്റാനോ നീക്കംചെയ്യാനോ സ്‌പർശിക്കുക"</string>
diff --git a/packages/SettingsLib/res/values-mn-rMN/strings.xml b/packages/SettingsLib/res/values-mn-rMN/strings.xml
index cc0e7cb..4aea631 100644
--- a/packages/SettingsLib/res/values-mn-rMN/strings.xml
+++ b/packages/SettingsLib/res/values-mn-rMN/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Манифест утгыг нь үл хамааран дурын апп-ыг гадаад санах ойд бичих боломжтой болгодог"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Үйл ажиллагааны хэмжээг өөрчилж болохуйц болгох"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Тодорхойлогч файлын утгыг үл хамааран, бүх үйл ажиллагааг олон цонхонд хэмжээг нь өөрчилж болохуйц болгох."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Десктоп нөөшлөлтийн нууц үг"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Десктоп бүрэн нөөцлөлт одоогоор хамгаалалтгүй байна"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Десктоп дээрх бүрэн нөөшлөлтийн нууц үгийг өөрчлөх буюу арилгахын тулд хүрнэ үү"</string>
diff --git a/packages/SettingsLib/res/values-mr-rIN/strings.xml b/packages/SettingsLib/res/values-mr-rIN/strings.xml
index b939ca0..ed57fb7 100644
--- a/packages/SettingsLib/res/values-mr-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-mr-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, कोणत्याही अॅपला बाह्य संचयनावर लेखन केले जाण्‍यासाठी पात्र बनविते"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"क्र‍ियाकलापाचा आकार बदलण्यायोग्य होण्याची सक्ती करा"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"मॅनिफेस्ट मूल्यांकडे दुर्लक्ष करून, एकाधिक-विंडोसाठी सर्व क्रियाकलापांचा आकार बदलण्यायोग्य करा"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"freeform विंडो सक्षम करा"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रायोगिक मुक्तस्वरूपाच्या विंडोसाठी समर्थन सक्षम करते."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटॉप बॅकअप संकेतशब्द"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटॉप पूर्ण बॅक अप सध्या संरक्षित नाहीत"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटॉपच्या पूर्ण बॅकअपसाठी असलेला संकेतशब्द बदलण्यासाठी किंवा काढून टाकण्यासाठी स्पर्श करा"</string>
diff --git a/packages/SettingsLib/res/values-ms-rMY/strings.xml b/packages/SettingsLib/res/values-ms-rMY/strings.xml
index 2e67752..1f72d04 100644
--- a/packages/SettingsLib/res/values-ms-rMY/strings.xml
+++ b/packages/SettingsLib/res/values-ms-rMY/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Menjadikan sebarang apl layak ditulis ke storan luaran, walau apa juga nilai manifesnya"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Paksa aktiviti supaya boleh diubah saiz"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Menjadikan semua aktiviti boleh diubah saiz untuk berbilang tetingkap, tanpa mengambil kira nilai manifes."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Kata laluan sandaran komputer meja"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sandaran penuh komputer meja tidak dilindungi pada masa ini"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Sentuh untuk menukar atau mengalih keluar kata laluan untuk sandaran penuh komputer meja"</string>
diff --git a/packages/SettingsLib/res/values-my-rMM/strings.xml b/packages/SettingsLib/res/values-my-rMM/strings.xml
index 002aed1..cd4812f 100644
--- a/packages/SettingsLib/res/values-my-rMM/strings.xml
+++ b/packages/SettingsLib/res/values-my-rMM/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ပြနေတဲ့ တန်ဖိုး ဘယ်လိုပဲရှိနေနေ၊ ဘယ် appကို မဆို အပြင် သိုလှောင်ခန်းသို့ ရေးသားခွင့် ပေးတယ်"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"လုပ်ဆောင်ချက်များ ဆိုက်ညှိရနိုင်ရန် လုပ်ခိုင်းပါ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"မန်နီးဖက်စ် တန်ဖိုးမရွေး၊ လုပ်ဆောင်ချက် အားလုံး ဆိုက်ညှိရနိုင်အောင် လုပ်ပေးပါ။"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Desktop အရန်စကားဝှက်"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"အလုပ်ခုံတွင် အရန်သိမ်းဆည်းခြင်းများကို လောလောဆယ် မကာကွယ်နိုင်ပါ။"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"အလုပ်ခုံ တွင် အရန်သိမ်းဆည်းခြင်းအပြည့်လုပ်ရန် အတွက် စကားဝှက်ဖယ်ရန် သို့ ပြောင်းရန် တို့ထိပါ။"</string>
diff --git a/packages/SettingsLib/res/values-nb/strings.xml b/packages/SettingsLib/res/values-nb/strings.xml
index a496a21..ae0b15d 100644
--- a/packages/SettingsLib/res/values-nb/strings.xml
+++ b/packages/SettingsLib/res/values-nb/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Gjør at apper kan skrives til ekstern lagring, uavhengig av manifestverdier"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Tving aktiviteter til å kunne endre størrelse"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Dette gjør at alle aktivitene kan endre størrelse for flervindusmodus, uavhengig av manifestverdier."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Passord for sikkerhetskopiering på datamaskin"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Fullstendig sikkerhetskopiering på datamaskin beskyttes ikke for øyeblikket."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Trykk for å endre eller fjerne passordet for fullstendige sikkerhetskopier på datamaskinen"</string>
diff --git a/packages/SettingsLib/res/values-ne-rNP/strings.xml b/packages/SettingsLib/res/values-ne-rNP/strings.xml
index 5c85c25..5885513 100644
--- a/packages/SettingsLib/res/values-ne-rNP/strings.xml
+++ b/packages/SettingsLib/res/values-ne-rNP/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"म्यानिफेेस्टको उपेक्षा गरी, कुनै पनि अनुप्रयोगलाई बाह्य भण्डारणमा लेख्न योग्य बनाउँछ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"गतिविधिहरू रिसाइज गर्नको लागि बाध्य गर्नुहोस्"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"म्यानिफेेस्ट मानहरूको ख्याल नगरी, बहु-विन्डोको लागि सबै रिसाइज गर्न सकिने गतिविधिहरू बनाउँछ।"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"फ्रीफर्म विन्डोहरू सक्रिय गर्नुहोस्"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"प्रयोगात्मक फ्रीफर्म विन्डोहरूका लागि समर्थनलाई सक्रिय गर्छ।"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"डेस्कटप ब्याकअप पासवर्ड"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"डेस्कटप पूर्ण जगेडाहरू हाललाई सुरक्षित छैनन्"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"डेस्कटप पूर्ण ब्याकअपको लागि पासवर्ड बदल्न वा हटाउन छुनुहोस्"</string>
diff --git a/packages/SettingsLib/res/values-nl/strings.xml b/packages/SettingsLib/res/values-nl/strings.xml
index 1afa444..1dd477d 100644
--- a/packages/SettingsLib/res/values-nl/strings.xml
+++ b/packages/SettingsLib/res/values-nl/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Hierdoor komt een app in aanmerking om te worden geschreven naar externe opslag, ongeacht de manifestwaarden"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Formaat activiteiten geforceerd aanpasbaar maken"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Hiermee wordt het formaat van alle activiteiten aanpasbaar gemaakt, ongeacht de manifestwaarden."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Vensters met vrije vorm inschakelen"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Schakelt ondersteuning in voor vensters met experimentele vrije vorm."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Wachtwoord desktopback-up"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Volledige back-ups naar desktops zijn momenteel niet beveiligd"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Raak dit aan om het wachtwoord voor volledige back-ups naar desktops te wijzigen of te verwijderen"</string>
diff --git a/packages/SettingsLib/res/values-pa-rIN/strings.xml b/packages/SettingsLib/res/values-pa-rIN/strings.xml
index ad3d3ed..85f9ffb 100644
--- a/packages/SettingsLib/res/values-pa-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-pa-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ਇੱਕ ਐਪ ਨੂੰ ਬਾਹਰਲੀ ਸਟੋਰੇਜ ਤੇ ਲਿਖਣ ਦੇ ਯੋਗ ਬਣਾਉਂਦਾ ਹੈ, ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ ਤੇ ਵਿਚਾਰ ਕੀਤੇ ਬਿਨਾਂ"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ਮੁੜ-ਆਕਾਰ ਬਦਲਣ ਲਈ ਸਰਗਰਮੀਆਂ \'ਤੇ ਜ਼ੋਰ ਦਿਓ"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ਮਲਟੀ-ਵਿੰਡੋ ਲਈ ਸਾਰੀਆਂ ਸਰਗਰਮੀਆਂ ਨੂੰ ਮੁੜ-ਆਕਾਰ ਵਿੱਚ ਲਿਆਉਂਦੀ ਹੈ, ਚਾਹੇ ਮੈਨੀਫੈਸਟ ਵੈਲਯੂਜ਼ ਕੁਝ ਵੀ ਹੋਣ।"</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"freeform windows ਨੂੰ ਯੋਗ ਬਣਾਓ"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ਪ੍ਰਯੋਗਾਤਮਕ freeform windows ਲਈ ਸਮਰਥਨ ਨੂੰ ਯੋਗ ਬਣਾਉਂਦੀ ਹੈ।"</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"ਡੈਸਕਟੌਪ ਬੈਕਅਪ ਪਾਸਵਰਡ"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਇਸ ਵੇਲੇ ਸੁਰੱਖਿਅਤ ਨਹੀਂ ਹਨ"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ਡੈਸਕਟੌਪ ਪੂਰੇ ਬੈਕਅਪਸ ਲਈ ਪਾਸਵਰਡ ਬਦਲਣ ਜਾਂ ਹਟਾਉਣ ਲਈ ਛੋਹਵੋ"</string>
diff --git a/packages/SettingsLib/res/values-pl/strings.xml b/packages/SettingsLib/res/values-pl/strings.xml
index d58070e..9f7c022 100644
--- a/packages/SettingsLib/res/values-pl/strings.xml
+++ b/packages/SettingsLib/res/values-pl/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Pozwala na zapis aplikacji w pamięci zewn. niezależnie od wartości w pliku manifestu"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Wymuś zmianę rozmiaru okien aktywności"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Umożliwia zmianę rozmiaru wszystkich okien aktywności w trybie wielu okien niezależnie od ustawień w pliku manifestu."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Włącz dowolny rozmiar okien"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Włącza obsługę eksperymentalnej funkcji dowolnego rozmiaru okien."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Hasło kopii zapasowej"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Pełne kopie zapasowe na komputerze nie są obecnie chronione"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Wybierz, aby zmienić lub usunąć hasło pełnych kopii zapasowych na komputerze stacjonarnym."</string>
diff --git a/packages/SettingsLib/res/values-pt-rBR/strings.xml b/packages/SettingsLib/res/values-pt-rBR/strings.xml
index 3b28043..dd4b58d 100644
--- a/packages/SettingsLib/res/values-pt-rBR/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rBR/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index c5f94cb..0cbe5e4 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualquer aplic. pode ser gravada no arm. ext., independ. dos valores do manif."</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar as atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Ativar janelas de forma livre"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Ativa a compatibilidade com janelas de forma livre experimentais."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Palavra-passe cópia do comp."</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"As cópias de segurança completas no ambiente de trabalho não estão atualmente protegidas"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a palavra-passe para cópias de segurança completas no ambiente de trabalho"</string>
diff --git a/packages/SettingsLib/res/values-pt/strings.xml b/packages/SettingsLib/res/values-pt/strings.xml
index 3b28043..dd4b58d 100644
--- a/packages/SettingsLib/res/values-pt/strings.xml
+++ b/packages/SettingsLib/res/values-pt/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Qualifica apps p/ gravação em armazenamento externo, independentemente de valores de manifestos"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forçar atividades a serem redimensionáveis"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Torna todas as atividades redimensionáveis para várias janelas, independentemente dos valores do manifesto."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Senha do backup local"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Os backups completos do computador não estão protegidos no momento"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Toque para alterar ou remover a senha de backups completos do desktop"</string>
diff --git a/packages/SettingsLib/res/values-ro/strings.xml b/packages/SettingsLib/res/values-ro/strings.xml
index c76faf0..a666da0 100644
--- a/packages/SettingsLib/res/values-ro/strings.xml
+++ b/packages/SettingsLib/res/values-ro/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Face orice aplicație eligibilă să fie scrisă în stocarea externă, indiferent de valorile manifestului"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Forțați redimensionarea activităților"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Permite redimensionarea tuturor activităților pentru modul cu ferestre multiple, indiferent de valorile manifestului."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Parolă copie rez. desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"În prezent, copiile de rezervă complete pe desktop nu sunt protejate"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Atingeţi pentru a modifica sau pentru a elimina parola pentru copiile de rezervă complete pe desktop"</string>
diff --git a/packages/SettingsLib/res/values-ru/strings.xml b/packages/SettingsLib/res/values-ru/strings.xml
index f1cd182..e93bae1 100644
--- a/packages/SettingsLib/res/values-ru/strings.xml
+++ b/packages/SettingsLib/res/values-ru/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Разрешает сохранение приложений на внешние накопители независимо от значения манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Изменение размера в многооконном режиме"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Позволяет менять размер в многооконном режиме (независимо от значений манифеста)"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Пароль для резервного копирования"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Полные резервные копии в настоящее время не защищены"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Изменить или удалить пароль для резервного копирования"</string>
diff --git a/packages/SettingsLib/res/values-si-rLK/strings.xml b/packages/SettingsLib/res/values-si-rLK/strings.xml
index eb13ce4..6753624 100644
--- a/packages/SettingsLib/res/values-si-rLK/strings.xml
+++ b/packages/SettingsLib/res/values-si-rLK/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"මැනිෆෙස්ට් අගයන් නොසලකා, ඕනෑම යෙදුමක් අභ්‍යන්තර ගබඩාවට ලිවීමට සුදුසුකම් ලබා දෙයි"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"ක්‍රියාකාරකම් ප්‍රතිප්‍රමාණ කළ හැකි බවට බල කරන්න"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"මැනිෆෙස්ට් අගයන් නොසලකා, සියලු ක්‍රියාකාරකම් බහු-කවුළු සඳහා ප්‍රතිප්‍රමාණ කළ හැකි බවට පත් කරයි."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"ඩෙස්ක්ටොප් උපස්ථ මුරපදය"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ දැනට ආරක්ෂා කර නොමැත"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ඩෙස්ක්ටොප් සම්පූර්ණ උපස්ථ සඳහා මුරපදය වෙනස් කිරීමට හෝ ඉවත් කිරීමට ස්පර්ශ කරන්න"</string>
diff --git a/packages/SettingsLib/res/values-sk/strings.xml b/packages/SettingsLib/res/values-sk/strings.xml
index b5b6d2a..7db7835 100644
--- a/packages/SettingsLib/res/values-sk/strings.xml
+++ b/packages/SettingsLib/res/values-sk/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Umožňuje zapísať akúkoľvek aplikáciu do externého úložiska bez ohľadu na hodnoty v manifeste"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Vynútiť možnosť zmeny veľkosti aktivít"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Veľkosti všetkých aktivít bude možné zmeniť na niekoľko okien (bez ohľadu na hodnoty manifestu)."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Heslo pre zálohy v počítači"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Úplné zálohy na počítači nie sú momentálne chránené"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotykom zmeníte alebo odstránite heslo pre úplné zálohy do počítača"</string>
diff --git a/packages/SettingsLib/res/values-sl/strings.xml b/packages/SettingsLib/res/values-sl/strings.xml
index cb107d7..ed37933 100644
--- a/packages/SettingsLib/res/values-sl/strings.xml
+++ b/packages/SettingsLib/res/values-sl/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsako aplikacijo zapisati v zunanjo shrambo"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Vsili povečanje velikosti za aktivnosti"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Poskrbi, da je ne glede na vrednosti v manifestu mogoče vsem aktivnostim povečati velikost za način z več okni."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Geslo za varn. kop. rač."</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Popolne varnostne kopije namizja trenutno niso zaščitene"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Dotaknite se, če želite spremeniti ali odstraniti geslo za popolno varnostno kopiranje namizja."</string>
diff --git a/packages/SettingsLib/res/values-sq-rAL/strings.xml b/packages/SettingsLib/res/values-sq-rAL/strings.xml
index c176f18..7f4d6a8 100644
--- a/packages/SettingsLib/res/values-sq-rAL/strings.xml
+++ b/packages/SettingsLib/res/values-sq-rAL/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bën që çdo aplikacion të jetë i përshtatshëm për t\'u shkruar në hapësirën ruajtëse të jashtme, pavarësisht nga vlerat e manifestit"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Detyro madhësinë e ndryshueshme për aktivitetet"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Bën që të gjitha aktivitetet të kenë madhësi të ndryshueshme për përdorimin me shumë dritare, pavarësisht vlerave të manifestit."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Aktivizo dritaret me formë të lirë"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Aktivizon mbështetjen për dritaret eksperimentale me formë të lirë."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Fjalëkalimi rezervë i kompjuterit"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Rezervimet e plota në kompjuter nuk janë të mbrojtura aktualisht"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Prek për të ndryshuar ose hequr fjalëkalimin për rezervime të plota të desktopit"</string>
diff --git a/packages/SettingsLib/res/values-sr/strings.xml b/packages/SettingsLib/res/values-sr/strings.xml
index 6b66094..9596ce5 100644
--- a/packages/SettingsLib/res/values-sr/strings.xml
+++ b/packages/SettingsLib/res/values-sr/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Омогућава уписивање свих апликација у спољну меморију, без обзира на вредности манифеста"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Принудно омогући промену величине активности"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Омогућава промену величине свих активности за режим са више прозора, без обзира на вредности манифеста."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Лозинка резервне копије за рачунар"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Резервне копије читавог система тренутно нису заштићене"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Додирните да бисте променили или уклонили лозинку за прављење резервних копија читавог система на рачунару"</string>
diff --git a/packages/SettingsLib/res/values-sv/strings.xml b/packages/SettingsLib/res/values-sv/strings.xml
index 40e1593..7d0d0a0 100644
--- a/packages/SettingsLib/res/values-sv/strings.xml
+++ b/packages/SettingsLib/res/values-sv/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Appen kan skrivas till extern lagring, oavsett manifestvärden"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Framtvinga storleksanpassning för aktiviteter"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Detta gör det möjligt att ändra storleken på alla aktiviteter i flerfönsterläge, oavsett manifestvärden."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Lösenord för säkerhetskopia av datorn"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"De fullständiga säkerhetskopiorna av datorn är för närvarande inte skyddade"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Tryck om du vill ändra eller ta bort lösenordet för fullständig säkerhetskopiering av datorn"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a014e1d..d1041da 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Huweka programu kwenye hifadhi ya nje, bila kujali maelezo"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Lazimisha shughuli ziweze kubadilishwa ukubwa"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Fanya shughuli zote ziweze kubadilishwa ukubwa kwa ajili ya dirisha nyingi, bila kujali thamani za faili ya maelezo."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Nenosiri la hifadhi rudufu ya eneo kazi"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Hifadhi rudufu kamili za eneo kazi hazijalindwa kwa sasa"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Gusa ili ubadilishe au uondoe nenosiri la hifadhi rudufu kamili za eneo kazi"</string>
diff --git a/packages/SettingsLib/res/values-ta-rIN/strings.xml b/packages/SettingsLib/res/values-ta-rIN/strings.xml
index 4f6ea57..e66f073 100644
--- a/packages/SettingsLib/res/values-ta-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-ta-rIN/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"மேனிஃபெஸ்ட் மதிப்புகளை பொருட்படுத்தாமல், எந்தப் பயன்பாட்டையும் வெளிப்புற சேமிப்பிடத்தில் எழுத அனுமதிக்கும்"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"செயல்பாடுகளை அளவுமாறக்கூடியதாக அமை"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"மேனிஃபெஸ்ட் மதிப்புகளைப் பொருட்படுத்தாமல், பல சாளரத்திற்கு எல்லா செயல்பாடுகளையும் அளவுமாறக்கூடியதாக அமைக்கும்."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"டெஸ்க்டாப் காப்புப்பிரதி கடவுச்சொல்"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"டெஸ்க்டாப்பின் முழு காப்புப்பிரதிகள் தற்போது பாதுகாக்கப்படவில்லை"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"டெஸ்க்டாப்பின் முழுமையான காப்புப்பிரதிகளுக்கான கடவுச்சொல்லை மாற்றுவதற்கு அல்லது அகற்றுவதற்குத் தொடவும்"</string>
diff --git a/packages/SettingsLib/res/values-te-rIN/strings.xml b/packages/SettingsLib/res/values-te-rIN/strings.xml
index a6d2140..80b84f0 100644
--- a/packages/SettingsLib/res/values-te-rIN/strings.xml
+++ b/packages/SettingsLib/res/values-te-rIN/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ఏ అనువర్తనాన్ని అయినా మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా బాహ్య నిల్వలో వ్రాయగలిగేలా అనుమతిస్తుంది"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"కార్యాచరణలను పరిమాణం మార్చగలిగేలా నిర్బంధించు"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"మానిఫెస్ట్ విలువలతో సంబంధం లేకుండా అన్ని కార్యాచరణలను బహుళ విండోల్లో సరిపోయేటట్లు పరిమాణం మార్చగలిగేలా చేస్తుంది."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"స్వతంత్ర రూప విండోలను ప్రారంభించండి"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"ప్రయోగాత్మక స్వతంత్ర రూప విండోలకు మద్దతును ప్రారంభిస్తుంది."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"డెస్క్‌టాప్ బ్యాకప్ పాస్‌వర్డ్"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌లు ప్రస్తుతం రక్షించబడలేదు"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"డెస్క్‌టాప్ పూర్తి బ్యాకప్‌ల కోసం పాస్‌వర్డ్‌ను మార్చడానికి లేదా తీసివేయడానికి తాకండి"</string>
diff --git a/packages/SettingsLib/res/values-th/strings.xml b/packages/SettingsLib/res/values-th/strings.xml
index de2f33d..6826419 100644
--- a/packages/SettingsLib/res/values-th/strings.xml
+++ b/packages/SettingsLib/res/values-th/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"ให้สามารถเขียนแอปต่างๆ ไปยังที่เก็บภายนอกได้ โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"บังคับให้กิจกรรมปรับขนาดได้"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"ทำให้กิจกรรมทั้งหมดปรับขนาดได้สำหรับหน้าต่างหลายบาน โดยไม่คำนึงถึงค่าในไฟล์ Manifest"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"รหัสผ่านการสำรองข้อมูลในเดสก์ท็อป"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"การสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป ไม่ได้รับการป้องกันในขณะนี้"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"แตะเพื่อเปลี่ยนหรือลบรหัสผ่านสำหรับการสำรองข้อมูลเต็มรูปแบบในเดสก์ท็อป"</string>
diff --git a/packages/SettingsLib/res/values-tl/strings.xml b/packages/SettingsLib/res/values-tl/strings.xml
index 231079b..8f62326 100644
--- a/packages/SettingsLib/res/values-tl/strings.xml
+++ b/packages/SettingsLib/res/values-tl/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Mara-write na sa external storage ang anumang app, anuman ang manifest value"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Sapilitang gawing resizable ang mga aktibidad"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Gawing resizable para sa multi-window ang lahat ng aktibidad, anuman ang mga manifest value."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Password ng pag-backup ng desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kasalukuyang hindi pinoprotektahan ang mga buong pag-backup ng desktop"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Pindutin upang baguhin o alisin ang password para sa mga buong pag-backup ng desktop"</string>
diff --git a/packages/SettingsLib/res/values-tr/strings.xml b/packages/SettingsLib/res/values-tr/strings.xml
index c44d7f8..5e0839a 100644
--- a/packages/SettingsLib/res/values-tr/strings.xml
+++ b/packages/SettingsLib/res/values-tr/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Bildirilen değerlerden bağımsız olarak uygulamaları harici depolamaya yazmak için uygun hale getirir"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Etkinlikleri yeniden boyutlandırılabilmeye zorla"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest değerlerinden bağımsız olarak, tüm etkinlikleri birden fazla pencerede yeniden boyutlandırılabilir hale getirir."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Masaüstü yedekleme şifresi"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Masaüstü tam yedeklemeleri şu an korunmuyor"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Masaüstü tam yedeklemelerinin şifresini değiştirmek veya kaldırmak için dokunun"</string>
diff --git a/packages/SettingsLib/res/values-uk/strings.xml b/packages/SettingsLib/res/values-uk/strings.xml
index d5dbe90..2448b23 100644
--- a/packages/SettingsLib/res/values-uk/strings.xml
+++ b/packages/SettingsLib/res/values-uk/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Додатки можна записувати на зовнішню пам’ять незалежно від значень маніфесту"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Примусово масштабувати активність"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Активність масштабуватиметься на кілька вікон, незалежно від значень у файлі маніфесту."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Увімкнути вікна довільного формату"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Увімкнуться експериментальні вікна довільного формату."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Пароль резерв.копії на ПК"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Повні резервні копії на комп’ютері наразі не захищені"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Торкніться, щоб змінити чи видалити пароль для повного резервного копіювання на комп’ютер"</string>
diff --git a/packages/SettingsLib/res/values-ur-rPK/strings.xml b/packages/SettingsLib/res/values-ur-rPK/strings.xml
index 4c9c178..0834303 100644
--- a/packages/SettingsLib/res/values-ur-rPK/strings.xml
+++ b/packages/SettingsLib/res/values-ur-rPK/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"‏manifest اقدار سے قطع نظر، کسی بھی ایپ کو بیرونی اسٹوریج پر لکھے جانے کا اہل بناتا ہے"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"سرگرمیوں کو ری سائز ایبل بنائیں"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"‏manifest اقدار سے قطع نظر، ملٹی ونڈو کیلئے تمام سرگرمیوں کو ری سائز ایبل بناتا ہے۔"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"ڈیسک ٹاپ کا بیک اپ پاس ورڈ"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"ڈیسک ٹاپ کے مکمل بیک اپس فی الحال محفوظ کیے ہوئے نہیں ہیں"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"ڈیسک ٹاپ کے مکمل بیک اپس کیلئے پاس ورڈ کو تبدیل کرنے یا ہٹانے کیلئے ٹچ کریں"</string>
diff --git a/packages/SettingsLib/res/values-uz-rUZ/strings.xml b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
index d138a28..d2d8b76 100644
--- a/packages/SettingsLib/res/values-uz-rUZ/strings.xml
+++ b/packages/SettingsLib/res/values-uz-rUZ/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Manifest qiymatidan qat’i nazar istalgan ilovani tashqi xotiraga saqlash imkonini beradi"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Harakatlarni moslashuvchan o‘lchamga keltirish"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Manifest qiymatidan qat’i nazar barcha harakatlarni ko‘p oynali rejimga moslashtiradi."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Zaxira nusxa uchun parol"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Kompyuterdagi zaxira nusxalar hozirgi vaqtda himoyalanmagan"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Ish stoli to\'liq zaxira nusxalari parolini o‘zgartirish yoki o‘chirish uchun bu yerni bosing."</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 7ab8b02..178e301 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Giúp ứng dụng bất kỳ đủ điều kiện được ghi vào bộ nhớ ngoài bất kể giá trị tệp kê khai là gì"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Buộc các hoạt động có thể thay đổi kích thước"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Giúp tất cả hoạt động có thể thay đổi kích thước cho nhiều cửa sổ bất kể giá trị tệp kê khai là gì."</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"Mật khẩu sao lưu của máy tính"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Sao lưu toàn bộ máy tính hiện không được bảo vệ"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Chạm để thay đổi hoặc xóa mật khẩu dành cho bộ sao lưu toàn bộ tới máy tính"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index 509ff88..5b96383 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允许将任何应用写入外部存储设备(无论清单值是什么)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"强制将活动设为可调整大小"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"将所有活动设为可配合多窗口环境调整大小(无论清单值是什么)。"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"桌面备份密码"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌面完整备份当前未设置密码保护"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"触摸可更改或删除用于桌面完整备份的密码"</string>
diff --git a/packages/SettingsLib/res/values-zh-rHK/strings.xml b/packages/SettingsLib/res/values-zh-rHK/strings.xml
index f323667..db5f09b 100644
--- a/packages/SettingsLib/res/values-zh-rHK/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rHK/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將所有應用程式寫入到外部儲存完間 (所有資訊清單值)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"強制可變更活動尺寸"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"在任何資訊清單值下,允許為多個視窗變更所有活動的尺寸。"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"桌面電腦備份密碼"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"桌上電腦的完整備份目前未受保護"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可更改或移除桌上電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zh-rTW/strings.xml b/packages/SettingsLib/res/values-zh-rTW/strings.xml
index c6ad832..787a442 100644
--- a/packages/SettingsLib/res/values-zh-rTW/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rTW/strings.xml
@@ -247,6 +247,10 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"允許將任何應用程式寫入外部儲存空間 (無論資訊清單值為何)"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"將活動強制設為可調整大小"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"將所有活動設為可配合多重視窗環境調整大小 (無論資訊清單值為何)。"</string>
+    <!-- no translation found for enable_freeform_support (1461893351278940416) -->
+    <skip />
+    <!-- no translation found for enable_freeform_support_summary (2252563497485436534) -->
+    <skip />
     <string name="local_backup_password_title" msgid="3860471654439418822">"電腦備份密碼"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"電腦完整備份目前未受保護"</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"輕觸即可變更或移除電腦完整備份的密碼"</string>
diff --git a/packages/SettingsLib/res/values-zu/strings.xml b/packages/SettingsLib/res/values-zu/strings.xml
index cb3670f..bf3addf 100644
--- a/packages/SettingsLib/res/values-zu/strings.xml
+++ b/packages/SettingsLib/res/values-zu/strings.xml
@@ -247,6 +247,8 @@
     <string name="force_allow_on_external_summary" msgid="3191952505860343233">"Yenza noma uluphi uhlelo lokusebenza lifaneleke ukuthi libhalwe kusitoreji sangaphandle, ngaphandle kwamavelu we-manifest"</string>
     <string name="force_resizable_activities" msgid="8615764378147824985">"Imisebenzi yamandla izonikezwa usayizi omusha"</string>
     <string name="force_resizable_activities_summary" msgid="4508217476997182216">"Yenza yonke imisebenzi ibe nosayizi abasha kuwindi lokuningi, ngokunganaki amanani we-manifest."</string>
+    <string name="enable_freeform_support" msgid="1461893351278940416">"Nika amandla amawindi e-freeform"</string>
+    <string name="enable_freeform_support_summary" msgid="2252563497485436534">"Inika amandla usekelo lwamawindi okuhlola e-freeform."</string>
     <string name="local_backup_password_title" msgid="3860471654439418822">"Iphasiwedi yokusekela ngokulondoloza ye-Desktop"</string>
     <string name="local_backup_password_summary_none" msgid="6951095485537767956">"Ukusekela ngokulondoloza okugcwele kwe-Desktop akuvikelekile okwamanje."</string>
     <string name="local_backup_password_summary_change" msgid="2731163425081172638">"Khetha ukushintsha noma ukususa iphasiwedi yokwenziwa kwezipele ngokugcwele kwideskithophu"</string>
diff --git a/packages/SettingsLib/res/values/arrays.xml b/packages/SettingsLib/res/values/arrays.xml
index 2a4efbd..1bce7f9 100644
--- a/packages/SettingsLib/res/values/arrays.xml
+++ b/packages/SettingsLib/res/values/arrays.xml
@@ -128,7 +128,7 @@
         <item>16777216</item>
     </string-array>
 
-    <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=30]-->
+    <!-- Summaries for logd limit size selection preference. [CHAR LIMIT=50]-->
     <string-array name="select_logd_size_summaries" >
         <item>Off</item>
         <item>64K per log buffer</item>
diff --git a/packages/SettingsLib/res/values/strings.xml b/packages/SettingsLib/res/values/strings.xml
index 7e22881..f7e25db 100644
--- a/packages/SettingsLib/res/values/strings.xml
+++ b/packages/SettingsLib/res/values/strings.xml
@@ -624,6 +624,11 @@
     <!-- UI debug setting: force allow on external summary [CHAR LIMIT=150] -->
     <string name="force_resizable_activities_summary">Makes all activities resizable for multi-window, regardless of manifest values.</string>
 
+    <!-- UI debug setting: enable freeform window support [CHAR LIMIT=50] -->
+    <string name="enable_freeform_support">Enable freeform windows</string>
+    <!-- UI debug setting: enable freeform window support summary [CHAR LIMIT=150] -->
+    <string name="enable_freeform_support_summary">Enables support for experimental freeform windows.</string>
+
     <!-- Local (desktop) backup password menu title [CHAR LIMIT=25] -->
     <string name="local_backup_password_title">Desktop backup password</string>
     <!-- Summary text of the "local backup password" setting when the user has not supplied a password -->
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index d31088c..f7a2d75 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -449,6 +449,11 @@
                 .addAction(cancelAction)
                 .build();
 
+        if (info.finished) {
+            Log.w(TAG, "Not sending progress notification because bugreport has finished already ("
+                    + info + ")");
+            return;
+        }
         NotificationManager.from(mContext).notify(TAG, info.pid, notification);
     }
 
@@ -628,7 +633,12 @@
         synchronized (BugreportProgressService.this) {
             mTakingScreenshot = flag;
             for (int i = 0; i < mProcesses.size(); i++) {
-                updateProgress(mProcesses.valueAt(i));
+                final BugreportInfo info = mProcesses.valueAt(i);
+                if (info.finished) {
+                    Log.d(TAG, "Not updating progress because share notification was already sent");
+                    continue;
+                }
+                updateProgress(info);
             }
         }
     }
diff --git a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
index 6bee767..8e8924a 100644
--- a/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
+++ b/packages/Shell/tests/src/com/android/shell/BugreportReceiverTest.java
@@ -142,6 +142,7 @@
     public void testProgress() throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
+        waitForScreenshotButtonEnabled(true);
 
         assertProgressNotification(NAME, "0.00%");
 
@@ -157,7 +158,7 @@
         Bundle extras =
                 sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE,
-                null, 1);
+                null, 1, true);
 
         assertServiceNotRunning();
     }
@@ -174,7 +175,7 @@
         Bundle extras =
                 sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath, mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, ZIP_FILE,
-                null, 2);
+                null, 2, true);
 
         assertServiceNotRunning();
     }
@@ -182,6 +183,7 @@
     public void testProgress_changeDetails() throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
+        waitForScreenshotButtonEnabled(true);
 
         DetailsUi detailsUi = new DetailsUi(mUiBot);
 
@@ -218,14 +220,33 @@
         Bundle extras = sendBugreportFinishedAndGetSharedIntent(PID, mPlainTextPath,
                 mScreenshotPath);
         assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NEW_NAME, TITLE,
-                mDescription, 1);
+                mDescription, 1, true);
 
         assertServiceNotRunning();
     }
 
+    /**
+     * Tests the scenario where the initial screenshot and dumpstate are finished while the user
+     * is changing the info in the details screen.
+     */
+    public void testProgress_bugreportAndScreenshotFinishedWhileChangingDetails() throws Exception {
+        bugreportFinishedWhileChangingDetailsTest(false);
+    }
+
+    /**
+     * Tests the scenario where dumpstate is finished while the user is changing the info in the
+     * details screen, but the initial screenshot finishes afterwards.
+     */
     public void testProgress_bugreportFinishedWhileChangingDetails() throws Exception {
+        bugreportFinishedWhileChangingDetailsTest(true);
+    }
+
+    private void bugreportFinishedWhileChangingDetailsTest(boolean waitScreenshot) throws Exception {
         resetProperties();
         sendBugreportStarted(1000);
+        if (waitScreenshot) {
+            waitForScreenshotButtonEnabled(true);
+        }
 
         DetailsUi detailsUi = new DetailsUi(mUiBot);
 
@@ -233,7 +254,7 @@
         detailsUi.nameField.setText(NEW_NAME);
         sendBugreportFinished(PID, mPlainTextPath, mScreenshotPath);
 
-        // Wait until the share notifcation is received...
+        // Wait until the share notification is received...
         mUiBot.getNotification(mContext.getString(R.string.bugreport_finished_title));
         // ...then close notification bar.
         mContext.sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
@@ -250,7 +271,7 @@
         // Finally, share bugreport.
         Bundle extras = acceptBugreportAndGetSharedIntent();
         assertActionSendMultiple(extras, BUGREPORT_FILE, BUGREPORT_CONTENT, PID, NAME, TITLE,
-                mDescription, 1);
+                mDescription, 1, waitScreenshot);
 
         assertServiceNotRunning();
     }
@@ -406,7 +427,7 @@
     private void assertActionSendMultiple(Bundle extras, String bugreportContent,
             String screenshotContent) throws IOException {
         assertActionSendMultiple(extras, bugreportContent, screenshotContent, PID, null, ZIP_FILE,
-                null, 0);
+                null, 0, false);
     }
 
     /**
@@ -420,10 +441,11 @@
      * @param title bugreport name as provided by the user (or received by dumpstate)
      * @param description bugreport description as provided by the user
      * @param numberScreenshots expected number of screenshots taken by Shell.
+     * @param renamedScreenshots whether the screenshots are expected to be renamed
      */
     private void assertActionSendMultiple(Bundle extras, String bugreportContent,
             String screenshotContent, int pid, String name, String title, String description,
-            int numberScreenshots) throws IOException {
+            int numberScreenshots, boolean renamedScreenshots) throws IOException {
         String body = extras.getString(Intent.EXTRA_TEXT);
         assertContainsRegex("missing build info",
                 SystemProperties.get("ro.build.description"), body);
@@ -480,7 +502,7 @@
         // Check internal screenshots.
         SortedSet<String> expectedNames = new TreeSet<>();
         for (int i = 1 ; i <= numberScreenshots; i++) {
-            String prefix = name != null ? name : Integer.toString(pid);
+            String prefix = renamedScreenshots  ? name : Integer.toString(pid);
             String expectedName = "screenshot-" + prefix + "-" + i + ".png";
             expectedNames.add(expectedName);
         }
@@ -592,7 +614,7 @@
 
     private UiObject waitForScreenshotButtonEnabled(boolean expectedEnabled) throws Exception {
         UiObject screenshotButton = getScreenshotButton();
-        int maxAttempts = SCREENSHOT_DELAY_SECONDS + 2;
+        int maxAttempts = SCREENSHOT_DELAY_SECONDS + 5;
         int i = 0;
         do {
             boolean enabled = screenshotButton.isEnabled();
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
new file mode 100644
index 0000000..f3be2ee
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/docked_divider_handle.xml b/packages/SystemUI/res/drawable/docked_divider_handle.xml
deleted file mode 100644
index 84c0343..0000000
--- a/packages/SystemUI/res/drawable/docked_divider_handle.xml
+++ /dev/null
@@ -1,22 +0,0 @@
-<!--
-Copyright (C) 2015 The Android Open Source Project
-
-   Licensed under the Apache License, Version 2 (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.
--->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-        android:shape="rectangle">
-    <size android:height="@dimen/docked_divider_handle_height"
-        android:width="@dimen/docked_divider_handle_width" />
-    <corners android:radius="1dp" />
-    <solid android:color="@color/docked_divider_handle" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/docked_stack_divider.xml b/packages/SystemUI/res/layout/docked_stack_divider.xml
index 22ed216..7ea5027 100644
--- a/packages/SystemUI/res/layout/docked_stack_divider.xml
+++ b/packages/SystemUI/res/layout/docked_stack_divider.xml
@@ -24,10 +24,9 @@
         android:id="@+id/docked_divider_background"
         android:background="@color/docked_divider_background"/>
 
-    <ImageButton
+    <com.android.systemui.stackdivider.DividerHandleView
         style="@style/DockedDividerHandle"
         android:id="@+id/docked_divider_handle"
-        android:background="@null"
-        android:src="@drawable/docked_divider_handle"/>
+        android:background="@null"/>
 
 </com.android.systemui.stackdivider.DividerView>
diff --git a/packages/SystemUI/res/layout/notification_guts.xml b/packages/SystemUI/res/layout/notification_guts.xml
index 3cdee64..071b7c8 100644
--- a/packages/SystemUI/res/layout/notification_guts.xml
+++ b/packages/SystemUI/res/layout/notification_guts.xml
@@ -29,25 +29,22 @@
         android:background="@color/notification_guts_text_color" >
 
     <!-- header -->
-    <FrameLayout
+    <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
-            android:paddingBottom="8dp" >
+            android:paddingBottom="8dp"
+            android:paddingTop="8dp"
+            android:id="@+id/notification_guts_header"
+            android:orientation="horizontal"
+            android:layout_gravity="center_vertical|start">
 
-        <LinearLayout
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:id="@+id/notification_guts_header"
-                android:orientation="horizontal"
-                android:layout_gravity="center_vertical|start"
-                android:layout_marginEnd="52dp">
-                    <ImageView
-                            android:id="@android:id/icon"
-                            android:layout_width="18dp"
-                            android:layout_height="18dp"
-                            android:layout_marginEnd="3dp"
-                            android:src="@android:drawable/arrow_down_float" />
-                    <TextView
+        <ImageView
+                android:id="@android:id/icon"
+                android:layout_width="18dp"
+                android:layout_height="18dp"
+                android:layout_marginEnd="3dp"
+                android:src="@android:drawable/arrow_down_float" />
+        <TextView
                             android:id="@+id/pkgname"
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
@@ -55,7 +52,7 @@
                             android:layout_marginStart="3dp"
                             android:layout_marginEnd="4dp"
                             android:textColor="@color/notification_guts_title_color" />
-                    <TextView
+        <TextView
                             android:layout_width="wrap_content"
                             android:layout_height="wrap_content"
                             android:id="@+id/debug_info"
@@ -64,18 +61,7 @@
                             android:layout_gravity="bottom|start"
                             android:visibility="gone"
                             android:textColor="#ffffff" />
-        </LinearLayout>
-
-        <ImageButton style="@android:style/Widget.Material.Light.Button.Borderless.Small"
-                android:id="@+id/notification_inspect_item"
-                android:layout_width="52dp"
-                android:layout_height="wrap_content"
-                android:layout_weight="0"
-                android:gravity="center"
-                android:layout_gravity="center_vertical|end"
-                android:contentDescription="@string/status_bar_notification_inspect_item_title"
-                android:src="@drawable/ic_settings" />
-    </FrameLayout>
+    </LinearLayout>
     <!-- Importance slider -->
     <LinearLayout
             android:layout_width="match_parent"
@@ -157,4 +143,34 @@
                          android:visibility="gone"/>
         </RadioGroup>
     </LinearLayout>
+    <!-- buttons -->
+    <LinearLayout
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:gravity="end"
+            android:paddingTop="8dp"
+            android:paddingBottom="16dp" >
+
+        <TextView
+            android:id="@+id/more_settings"
+            android:text="@string/notification_more_settings"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.NotificationGuts"
+            android:background="@drawable/btn_borderless_rect"
+            android:gravity="center"
+            android:paddingEnd="24dp"
+            android:paddingStart="12dp"
+            android:focusable="true" />
+
+        <TextView
+            android:id="@+id/done"
+            android:text="@string/notification_done"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:textAppearance="@style/TextAppearance.NotificationGuts"
+            android:background="@drawable/btn_borderless_rect"
+            android:gravity="center"
+            android:focusable="true"/>
+    </LinearLayout>
 </com.android.systemui.statusbar.NotificationGuts>
diff --git a/packages/SystemUI/res/layout/recents_task_view.xml b/packages/SystemUI/res/layout/recents_task_view.xml
index 2b82b05..5b44c17 100644
--- a/packages/SystemUI/res/layout/recents_task_view.xml
+++ b/packages/SystemUI/res/layout/recents_task_view.xml
@@ -34,9 +34,10 @@
             android:layout_gravity="bottom|right"
             android:layout_marginRight="15dp"
             android:layout_marginBottom="15dp"
-            android:translationZ="2dp"
+            android:translationZ="4dp"
             android:contentDescription="@string/recents_lock_to_app_button_label"
-            android:background="@drawable/recents_lock_to_task_button_bg">
+            android:background="@drawable/recents_lock_to_task_button_bg"
+            android:visibility="invisible">
             <ImageView
                 android:layout_width="@dimen/recents_lock_to_app_icon_size"
                 android:layout_height="@dimen/recents_lock_to_app_icon_size"
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index f81bf23..0187993 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Wys hierdie kennisgewings sonder geluide"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Wys boaan die kennisgewinglys en maak \'n geluid"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Verskyn vlugtig op die skerm en maak \'n geluid"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Meer instellings"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Klaar"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleure"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Aandkleure"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Gepasmaakte kleure"</string>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index d96e790..503a767 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"እነዚህን ማሳወቂያዎች በጸጥታ አሳይ"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"በማሳወቂያዎች ዝርዝር ላይኛው ክፍል ላይ አሳይና ድምፅ አሰማ"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"ወደ ገጸ ማያው ይመልከቱና ድምፅ ይቅረጹ"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"ተጨማሪ ቅንብሮች"</string>
+    <string name="notification_done" msgid="5279426047273930175">"ተከናውኗል"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"መደበኛ ቀለሞች"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"የለሊት ቀለሞች"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ብጁ ቀለሞች"</string>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index b3e494c..d89d036 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -464,6 +464,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"عرض هذه الإشعارات بدون تنبيه صوتي"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"العرض أعلى قائمة الإشعارات مع تنبيه صوتي"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"الظهور سريعًا على الشاشة مع تنبيه صوتي"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"المزيد من الإعدادات"</string>
+    <string name="notification_done" msgid="5279426047273930175">"تم"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ألوان عادية"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ألوان ليلية"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ألوان مخصصة"</string>
diff --git a/packages/SystemUI/res/values-az-rAZ/strings.xml b/packages/SystemUI/res/values-az-rAZ/strings.xml
index 4efc5df..55f0841 100644
--- a/packages/SystemUI/res/values-az-rAZ/strings.xml
+++ b/packages/SystemUI/res/values-az-rAZ/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildişləri səssiz göstərin"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Bildirişlər siyahısında yuxarıda göstərin və səsli edin"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Ekranda nəzər salın və səsli edin"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Daha çox ayar"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Hazırdır"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normal rənglər"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Gecə rəngləri"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Xüsusi rənglər"</string>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index f482e96..4056963 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -455,12 +455,14 @@
     <string name="low_importance" msgid="4109929986107147930">"Mala važnost"</string>
     <string name="default_importance" msgid="8192107689995742653">"Uobičajena važnost"</string>
     <string name="high_importance" msgid="1527066195614050263">"Velika važnost"</string>
-    <string name="max_importance" msgid="5089005872719563894">"Najveća važnost"</string>
+    <string name="max_importance" msgid="5089005872719563894">"Važnost: hitno"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ova obaveštenja se nikada ne prikazuju"</string>
     <string name="notification_importance_low" msgid="4383563267370859725">"Prikazuju se u dnu liste obaveštenja bez zvuka"</string>
     <string name="notification_importance_default" msgid="4926529615920610817">"Ova obaveštenja se prikazuju bez zvuka"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Prikazuju se u vrhu liste obaveštenja i emituje se zvuk"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Nakratko se prikazuju na ekranu i emituje se zvuk"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Još podešavanja"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normalne boje"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 95c4a22..93c26a4 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Тези известия се показват без звук"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Показване най-горе в списъка с известия и издаване на звуков сигнал"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Показване на екрана и издаване на звуков сигнал"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Още настройки"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Нормални цветове"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Нощни цветове"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Персонализирани цветове"</string>
diff --git a/packages/SystemUI/res/values-bn-rBD/strings.xml b/packages/SystemUI/res/values-bn-rBD/strings.xml
index 38885d5..939465b6 100644
--- a/packages/SystemUI/res/values-bn-rBD/strings.xml
+++ b/packages/SystemUI/res/values-bn-rBD/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"নিঃশব্দে এই বিজ্ঞপ্তিগুলি দেখানো হয়"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"বিজ্ঞপ্তি তালিকার শীর্ষে দেখানো হয় এবং শব্দ করে"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"স্ক্রীনের উপরে দেখানো হয় এবং শব্দ করে"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"আরো সেটিংস"</string>
+    <string name="notification_done" msgid="5279426047273930175">"সম্পন্ন"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"স্বাভাবিক রঙ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"রাতের রঙ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"কাস্টম রঙ"</string>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index d27c3ee..e19aa0e 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostra aquestes notificacions de manera silenciosa"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostra a la part superior de la llista de notificacions i emet un so"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostra a la pantalla i emet un so"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Més opcions"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Fet"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Colors normals"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Colors nocturns"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Colors personalitzats"</string>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 4f26dc1..b1cd561 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Tato oznámení zobrazovat bez zvukového upozornění"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Tato oznámení zobrazovat na začátku seznamu a upozornit na ně zvukem"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Tato oznámení zobrazovat přímo na obrazovce a upozornit na ně zvukem"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Další nastavení"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normální barvy"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Noční barvy"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastní barvy"</string>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index 3f868a8..2100c57 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse underretninger lydløst"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på listen over underretninger, og giv lyd"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Vis på skærmen, og giv lyd"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Flere indstillinger"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Færdig"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Almindelige farver"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nattefarver"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Tilpassede farver"</string>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 4c87758..1ad5b26 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Diese Benachrichtigungen ohne Ton anzeigen"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mit Ton ganz oben in der Benachrichtigungsliste anzeigen"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mit Ton auf dem Display einblenden"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Weitere Einstellungen"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Fertig"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Standardfarben"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nachtfarben"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Benutzerdefinierte Farben"</string>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index 21e1eee..f56d630 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Να εμφανίζονται αυτές οι ειδοποιήσεις χωρίς ήχο"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Να εμφανίζονται στην κορυφή της λίστας ειδοποιήσεων με ήχο"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Να προβάλλονται στην οθόνη και να συνοδεύονται από κάποιον ήχο"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Περισσότερες ρυθμίσεις"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Τέλος"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Κανονικά χρώματα"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Νυχτερινά χρώματα"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Προσαρμοσμένα χρώματα"</string>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index fa8b6c33..f6fc997 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index fa8b6c33..f6fc997 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index fa8b6c33..f6fc997 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Silently show these notifications"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Show at the top of the notifications list and make sound"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Peek onto the screen and make sound"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"More settings"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Finished"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normal colours"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Night colours"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Customised colours"</string>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 54850f0..fd59418 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de manera silenciosa"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Más opciones de configuración"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 41d83dc..223e684 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificaciones de forma silenciosa"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar en la parte superior de la lista de notificaciones y emitir sonido"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar en la pantalla y emitir sonido"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Más ajustes"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Listo"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Colores normales"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Colores nocturnos"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Colores personalizados"</string>
diff --git a/packages/SystemUI/res/values-et-rEE/strings.xml b/packages/SystemUI/res/values-et-rEE/strings.xml
index 9bb7898..f50e78c 100644
--- a/packages/SystemUI/res/values-et-rEE/strings.xml
+++ b/packages/SystemUI/res/values-et-rEE/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Kuva need märguanded vaikselt"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Kuva märguannete loendi ülaosas koos heliga"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Kuva ekraani servas koos heliga"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Rohkem seadeid"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Tavalised värvid"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Öised värvid"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Kohandatud värvid"</string>
diff --git a/packages/SystemUI/res/values-eu-rES/strings.xml b/packages/SystemUI/res/values-eu-rES/strings.xml
index e62303a..c481f52 100644
--- a/packages/SystemUI/res/values-eu-rES/strings.xml
+++ b/packages/SystemUI/res/values-eu-rES/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Erakutsi jakinarazpen hauek, baina soinurik egin gabe"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Erakutsi jakinarazpen hauek zerrendaren goialdean eta egin soinua"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Agerrarazi jakinarazpen hauek pantailan eta egin soinua"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Ezarpen gehiago"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Eginda"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Kolore normalak"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Gaueko koloreak"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Kolore pertsonalizatuak"</string>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index f45c01b..3dee7c9 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"این اعلان‌ها بی‌صدا نشان داده شوند"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"در بالای فهرست اعلان‌ها و به همراه صدا نشان داده شود"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"در جلوی صفحه به همراه صدا نشان داده شود"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"تنظیمات بیشتر"</string>
+    <string name="notification_done" msgid="5279426047273930175">"تمام"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"رنگ‌های عادی"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"رنگ‌های شب"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"رنگ‌های سفارشی"</string>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index af1a1e5..4a5c302 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Näytä nämä ilmoitukset huomaamattomasti"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Näytä ilmoitukset luettelon kärjessä ja toista merkkiääni"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Näytä ilmoitus näytöllä ja toista äänimerkki"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Lisäasetukset"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Valmis"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Tavalliset värit"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Yövärit"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Muokatut värit"</string>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 20a8bdc..2a4f4d9 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 8e76ee8..928a8b3 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Afficher ces notifications en mode silencieux"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Afficher en haut de la liste des notifications et émettre un son"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Afficher sur l\'écran et émettre un son"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Plus de paramètres"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Terminé"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Couleurs normales"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Couleurs nocturnes"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Couleurs personnalisées"</string>
diff --git a/packages/SystemUI/res/values-gl-rES/strings.xml b/packages/SystemUI/res/values-gl-rES/strings.xml
index 4562d89b..2a951f7 100644
--- a/packages/SystemUI/res/values-gl-rES/strings.xml
+++ b/packages/SystemUI/res/values-gl-rES/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificacións de forma silenciosa"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificacións e emitir son"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar na pantalla e emitir son"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Máis opcións"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Feito"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Cores nocturnas"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
diff --git a/packages/SystemUI/res/values-gu-rIN/strings.xml b/packages/SystemUI/res/values-gu-rIN/strings.xml
index 69174ef..f331ef9 100644
--- a/packages/SystemUI/res/values-gu-rIN/strings.xml
+++ b/packages/SystemUI/res/values-gu-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"આ સૂચનાઓ ચુપચાપ બતાવો"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"સૂચનાઓની સૂચિની ટોચ પર બતાવો અને અવાજ કરો"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"સ્ક્રીન પર ત્વરિત દ્રષ્ટિ કરો અને અવાજ કરો"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"વધુ સેટિંગ્સ"</string>
+    <string name="notification_done" msgid="5279426047273930175">"થઈ ગયું"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"સામાન્ય રંગો"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"રાત્રિ રંગો"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"કસ્ટમ રંગો"</string>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 1ab7f71..b31c1e0 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ये नोटिफिकेशन मौन रूप से दिखाएं"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"नोटिफिकेशन सूची में सबसे ऊपर दिखाएं और ध्वनि चलाएं"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"स्‍क्रीन पर एक झलक दिखाएं और ध्‍वनि चलाएं"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"और सेटिंग"</string>
+    <string name="notification_done" msgid="5279426047273930175">"हो गया"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"रात्रि के रंग"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"कस्टम रंग"</string>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index a67258c..3bef6e9 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -461,6 +461,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži te obavijesti tiho"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu popisa obavijesti i emitiraj zvučni signal"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Prikaži na zaslonu i emitiraj zvučni signal"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Više postavki"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Gotovo"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Uobičajene boje"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Noćne boje"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Prilagođene boje"</string>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 8589e95..8dc9a19 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Hang nélkül jelennek meg ezek az értesítések"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Az értesítési lista tetején jelennek meg hangjelzéssel"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Az értesítések felugranak a képernyőn hangjelzéssel"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"További beállítások"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Kész"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Hagyományos színek"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Esti színek"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Egyéni színek"</string>
diff --git a/packages/SystemUI/res/values-hy-rAM/strings.xml b/packages/SystemUI/res/values-hy-rAM/strings.xml
index 1b8de04..99d6980 100644
--- a/packages/SystemUI/res/values-hy-rAM/strings.xml
+++ b/packages/SystemUI/res/values-hy-rAM/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Ցուցադրել այս ծանուցումներն առանց ձայնային ազդանշանի"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Ցուցադրել ծանուցումների ցանկի վերևում և հնչեցնել ձայնային ազդանշան"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Ցուցադրել էկրանին և հնչեցնել ձայնային ազդանշան"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Այլ կարգավորումներ"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Պատրաստ է"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Սովորական գույներ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Գիշերային գույներ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Հատուկ գույներ"</string>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 9075484..f6124db 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan notifikasi ini tanpa suara"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan di bagian atas daftar notifikasi dan bunyikan suara"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Muncul di layar dan bunyikan suara"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Setelan lainnya"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Warna normal"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Warna khusus"</string>
diff --git a/packages/SystemUI/res/values-is-rIS/strings.xml b/packages/SystemUI/res/values-is-rIS/strings.xml
index 556018c..7ea1746 100644
--- a/packages/SystemUI/res/values-is-rIS/strings.xml
+++ b/packages/SystemUI/res/values-is-rIS/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Sýna þessar tilkynningar án hljóðs"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Sýna efst á tilkynningalistanum og spila hljóð"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Birta á skjánum og spila hljóð"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Fleiri stillingar"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Lokið"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Venjulegir litir"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Næturlitir"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Sérsniðnir litir"</string>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index b49c387..b395f8b 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostra silenziosamente queste notifiche"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostra nella parte superiore dell\'elenco delle notifiche e riproduci suono"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Apri sullo schermo e riproduci suono"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Altre impostazioni"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Fine"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Colori normali"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Colori per la notte"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Colori personalizzati"</string>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index e6ac5af..2c894f5 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"הצג את ההודעות האלה בלי להשמיע צליל"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"הצג בחלק העליון של רשימת ההודעות והשמע צליל"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"הצג לרגע על המסך והשמע צליל"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"הגדרות נוספות"</string>
+    <string name="notification_done" msgid="5279426047273930175">"סיום"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"צבעים רגילים"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"צבעי לילה"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"צבעים מותאמים אישית"</string>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index e7e3a86..580d995 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"この通知をマナーモードで表示する"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"通知リストの先頭に表示し、音声でも知らせる"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"画面に数秒間表示し、音声でも知らせる"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"詳細設定"</string>
+    <string name="notification_done" msgid="5279426047273930175">"完了"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"標準の色"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"夜間の色"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"カスタムの色"</string>
diff --git a/packages/SystemUI/res/values-ka-rGE/strings.xml b/packages/SystemUI/res/values-ka-rGE/strings.xml
index 79e0f4f..7a51668 100644
--- a/packages/SystemUI/res/values-ka-rGE/strings.xml
+++ b/packages/SystemUI/res/values-ka-rGE/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ამ შეტყობინებების უხმოდ ჩვენება"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"ამ შეტყობინებების სიის თავში, ხმოვან სიგნალთან ერთად ჩვენება"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"ამ შეტყობინებების პირდაპირ ეკრანზე, ხმოვან სიგნალთან ერთად ჩვენება"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"დამატებითი პარამეტრები"</string>
+    <string name="notification_done" msgid="5279426047273930175">"მზადაა"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ჩვეულებრივი ფერები"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ღამის ფერები"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"მორგებული ფერები"</string>
diff --git a/packages/SystemUI/res/values-kk-rKZ/strings.xml b/packages/SystemUI/res/values-kk-rKZ/strings.xml
index 5187b54..eb8995e 100644
--- a/packages/SystemUI/res/values-kk-rKZ/strings.xml
+++ b/packages/SystemUI/res/values-kk-rKZ/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Осы хабарландыруларды үнсіз көрсету"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Хабарландыруларды тізімінің жоғарғы жағында көрсету және дыбыс шығару"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Экранға бекіту және дыбыс шығару"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Қосымша параметрлер"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Дайын"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Қалыпты түстер"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Түнгі түстер"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Арнаулы түстер"</string>
diff --git a/packages/SystemUI/res/values-km-rKH/strings.xml b/packages/SystemUI/res/values-km-rKH/strings.xml
index 5665a90..5c10213 100644
--- a/packages/SystemUI/res/values-km-rKH/strings.xml
+++ b/packages/SystemUI/res/values-km-rKH/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"បង្ហាញការជូនដំណឹងទាំងនេះស្ងាត់ៗ"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"បង្ហាញនៅផ្នែកខាងលើបញ្ជីនៃការជូនដំណឹង និងបន្លឺសំឡេង"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"លោតបង្ហាញនៅលើអេក្រង់ និងបន្លឺសំឡេង"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"ការកំណត់ច្រើនទៀត"</string>
+    <string name="notification_done" msgid="5279426047273930175">"រួចរាល់"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ពណ៌ធម្មតា"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ពណ៌ពេលយប់"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ពណ៌ផ្ទាល់ខ្លួន"</string>
diff --git a/packages/SystemUI/res/values-kn-rIN/strings.xml b/packages/SystemUI/res/values-kn-rIN/strings.xml
index 0326a67..28b2de5 100644
--- a/packages/SystemUI/res/values-kn-rIN/strings.xml
+++ b/packages/SystemUI/res/values-kn-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ಈ ಅಧಿಸೂಚನೆಗಳನ್ನು ಸ್ಥಬ್ಧವಾಗಿ ತೋರಿಸು"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"ಅಧಿಸೂಚನೆಗಳ ಪಟ್ಟಿಯ ಮೇಲ್ಭಾಗದಲ್ಲಿ ತೋರಿಸು ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"ಪರದೆಯನ್ನು ವೀಕ್ಷಿಸಿ ಮತ್ತು ಧ್ವನಿ ಮಾಡು"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"ಹೆಚ್ಚಿನ ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
+    <string name="notification_done" msgid="5279426047273930175">"ಮುಗಿದಿದೆ"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ಸಾಮಾನ್ಯ ಬಣ್ಣಗಳು"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ರಾತ್ರಿ ಬಣ್ಣಗಳು"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ಕಸ್ಟಮ್ ಬಣ್ಣಗಳು"</string>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index b910c04..110376f 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"무음으로 알림 표시"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"알림 목록 상단에 표시하고 소리로 알림"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"화면에 표시하고 소리로 알림"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"설정 더보기"</string>
+    <string name="notification_done" msgid="5279426047273930175">"완료"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"일반 색상"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"야간 색상"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"맞춤 색상"</string>
diff --git a/packages/SystemUI/res/values-ky-rKG/strings.xml b/packages/SystemUI/res/values-ky-rKG/strings.xml
index e703e00..ee2ef5d 100644
--- a/packages/SystemUI/res/values-ky-rKG/strings.xml
+++ b/packages/SystemUI/res/values-ky-rKG/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Бул эскертмелер үнсүз көрсөтүлсүн"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Эскертмелер тизмесинин эң жогорусунда үн чыгарып көрсөтүлсүн"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Үн менен коштолуп, экранга чыгарылсын"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Дагы жөндөөлөр"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Аткарылды"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Кадимки түстөр"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Түнкү түстөр"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Ыңгайлаштырылган түстөр"</string>
diff --git a/packages/SystemUI/res/values-lo-rLA/strings.xml b/packages/SystemUI/res/values-lo-rLA/strings.xml
index 8e43408..ed103ea 100644
--- a/packages/SystemUI/res/values-lo-rLA/strings.xml
+++ b/packages/SystemUI/res/values-lo-rLA/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ສະແດງການແຈ້ງເຕືອນເຫຼົ່ານີ້ແບບບໍ່ມີສຽງ"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"ສະແດງຢູ່ສ່ວນເທິງຂອງລາຍການແຈ້ງເຕືອນ ແລະສົ່ງສຽງດັງ"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"ເດັ້ງຂຶ້ນເທິງຫນ້າຈໍ ແລະສົ່ງສຽງດັງ"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"​ການ​ຕັ້ງ​ຄ່າ​ເພີ່ມ​ເຕີມ"</string>
+    <string name="notification_done" msgid="5279426047273930175">"ສຳເລັດແລ້ວ"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ສີ​ປົກ​ກະ​ຕິ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ສີ​ຕອນ​ກາງ​ຄືນ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ສີແບບກຳນົດເອງ"</string>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 04066a7..ba98e2b 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Tyliai rodyti šiuos pranešimus"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Rodyti pranešimų sąrašo viršuje ir skambėti"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Rodyti ekrane ir skambėti"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Daugiau nustatymų"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Atlikta"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Įprastos spalvos"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nakties spalvos"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Tinkintos spalvos"</string>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 649d07b..0143fea 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -461,6 +461,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Rādīt šos paziņojumus bez skaņas signāla"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Rādīt paziņojumu saraksta augšdaļā un ar skaņas signālu"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Rādīt ekrānā ar skaņas signālu"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Citi iestatījumi"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Gatavs"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Parastas krāsas"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nakts krāsas"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Pielāgotas krāsas"</string>
diff --git a/packages/SystemUI/res/values-mk-rMK/strings.xml b/packages/SystemUI/res/values-mk-rMK/strings.xml
index 928bbcd..c573139 100644
--- a/packages/SystemUI/res/values-mk-rMK/strings.xml
+++ b/packages/SystemUI/res/values-mk-rMK/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Тивко прикажувај ги известувањава"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Прикажувај ги на врвот на списокот со известувања и дај звучен сигнал"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Појави се на екранот и дај звучен сигнал"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Повеќе поставки"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Нормални бои"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Ноќни бои"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Приспособени бои"</string>
diff --git a/packages/SystemUI/res/values-ml-rIN/strings.xml b/packages/SystemUI/res/values-ml-rIN/strings.xml
index 2f4b81a..c6a08e6 100644
--- a/packages/SystemUI/res/values-ml-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ml-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ഈ അറിയിപ്പുകൾ നിശബ്ദമായി കാണിക്കുക"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"അറിയിപ്പ് ലിസ്റ്റിന്റെ ഏറ്റവും മുകളിൽ കാണിക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"സ്ക്രീനിൽ ദൃശ്യമാക്കുക, ശബ്ദമുണ്ടാക്കുക"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"കൂടുതൽ ക്രമീകരണം"</string>
+    <string name="notification_done" msgid="5279426047273930175">"പൂർത്തിയായി"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"സാധാരണ വര്‍ണ്ണങ്ങൾ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"രാത്രി വര്‍ണ്ണങ്ങൾ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ഇഷ്ടാനുസൃത വര്‍ണ്ണങ്ങൾ"</string>
diff --git a/packages/SystemUI/res/values-mn-rMN/strings.xml b/packages/SystemUI/res/values-mn-rMN/strings.xml
index 3dd084e..91c817a 100644
--- a/packages/SystemUI/res/values-mn-rMN/strings.xml
+++ b/packages/SystemUI/res/values-mn-rMN/strings.xml
@@ -458,6 +458,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Эдгээр мэдэгдлийг дуугүй харуулах"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Мэдэгдлийг жагсаалтын эхэнд дуутай харуулах"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Дэлгэцэнд яаралтайгаар дуутай гаргах"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Бусад тохиргоо"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Дууссан"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Хэвийн өнгө"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Шөнийн өнгө"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Өгөгдмөл өнгө"</string>
diff --git a/packages/SystemUI/res/values-mr-rIN/strings.xml b/packages/SystemUI/res/values-mr-rIN/strings.xml
index 59eadf1..5d3a96f 100644
--- a/packages/SystemUI/res/values-mr-rIN/strings.xml
+++ b/packages/SystemUI/res/values-mr-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"या सूचना शांतपणे दर्शवा"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीच्या शीर्षस्थानी दर्शवा आणि ध्वनी चालू करा"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रीनवर डोकावून पहा आणि ध्वनी चालू करा"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"अधिक सेटिंग्ज"</string>
+    <string name="notification_done" msgid="5279426047273930175">"पूर्ण झाले"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रंग"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"रात्रीचे रंग"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"सानुकूल रंग"</string>
diff --git a/packages/SystemUI/res/values-ms-rMY/strings.xml b/packages/SystemUI/res/values-ms-rMY/strings.xml
index 5dd221a..f0a013c 100644
--- a/packages/SystemUI/res/values-ms-rMY/strings.xml
+++ b/packages/SystemUI/res/values-ms-rMY/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Tunjukkan pemberitahuan ini secara senyap"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Tunjukkan pada bahagian atas senarai pemberitahuan dan bunyikan"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Intai pada skrin dan bunyikan"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Lagi tetapan"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Selesai"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Warna biasa"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Warna malam"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Warna tersuai"</string>
diff --git a/packages/SystemUI/res/values-my-rMM/strings.xml b/packages/SystemUI/res/values-my-rMM/strings.xml
index 293e010..75008cb 100644
--- a/packages/SystemUI/res/values-my-rMM/strings.xml
+++ b/packages/SystemUI/res/values-my-rMM/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ဤသတိပေးချက်များကို တိတ်တဆိတ်ပြပါ"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"သတိပေးချက်စာရင်းများ၏ ထိပ်တွင်ပြကာ အသံဖွင့်ပါ"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"မျက်နှာပြင်ပေါ်သို့ ဖော်ပြကာ အသံဖွင့်ပါ"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"နောက်ထပ် ဆက်တင်များ"</string>
+    <string name="notification_done" msgid="5279426047273930175">"ပြီးပါပြီ"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ပုံမှန် အရောင်များ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ည အရောင်များ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"စိတ်ကြိုက် အရောင်များ"</string>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index ffc2fcf..295a49a 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Vis disse varslene uten lyd"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Vis øverst på varsellisten med lyd"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Vis fort på skjermen med lyd"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Flere innstillinger"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Ferdig"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normale farger"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nattfarger"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Spesialtilpassede farger"</string>
diff --git a/packages/SystemUI/res/values-ne-rNP/strings.xml b/packages/SystemUI/res/values-ne-rNP/strings.xml
index 6f40d55..d0aa510 100644
--- a/packages/SystemUI/res/values-ne-rNP/strings.xml
+++ b/packages/SystemUI/res/values-ne-rNP/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"यी सूचनाहरू बिना आवाज देखाउनुहोस्"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"सूचना सूचीको शीर्षमा देखाउनुहोस् र आवाज निकाल्नुहोस्"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"स्क्रिनमा हेर्नुहोस् र आवाज निकाल्नुहोस्"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"थप सेटिङहरू"</string>
+    <string name="notification_done" msgid="5279426047273930175">"सम्पन्‍न भयो"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"सामान्य रङहरू"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"रात्री रङहरू"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"अनुकूलन रङहरू"</string>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 27eb1d11..75812ad 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Deze meldingen zonder geluid weergeven"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Boven aan de lijst met meldingen weergeven en geluid laten horen"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Op het scherm weergeven en geluid laten horen"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Meer instellingen"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Gereed"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normale kleuren"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nachtkleuren"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Aangepaste kleuren"</string>
diff --git a/packages/SystemUI/res/values-pa-rIN/strings.xml b/packages/SystemUI/res/values-pa-rIN/strings.xml
index 2dd91ec..fc5a3ea 100644
--- a/packages/SystemUI/res/values-pa-rIN/strings.xml
+++ b/packages/SystemUI/res/values-pa-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ਇਹਨਾਂ ਸੂਚਨਾਵਾਂ ਨੂੰ ਚੁੱਪਚਾਪ ਢੰਗ ਨਾਲ ਵਿਖਾਓ"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"ਸੂਚਨਾਵਾਂ ਸੂਚੀ ਦੇ ਸਿਖਰ \'ਤੇ ਵਿਖਾਓ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"ਸਕਰੀਨ \'ਤੇ ਝਾਤੀ ਮਾਰੋ ਅਤੇ ਆਵਾਜ਼ ਕਰੋ"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"ਹੋਰ ਸੈਟਿੰਗਾਂ"</string>
+    <string name="notification_done" msgid="5279426047273930175">"ਹੋ ਗਿਆ"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"ਸਧਾਰਨ ਰੰਗ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"ਰਾਤ ਦੇ ਰੰਗ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"ਕਸਟਮ ਰੰਗ"</string>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index bf222bc..8ef50c9 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Pokazuj te powiadomienia bez sygnału dźwiękowego"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Pokazuj na górze listy powiadomień i sygnalizuj dźwiękiem"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Wyświetlaj na ekranie i odtwarzaj dźwięk"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Więcej ustawień"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Gotowe"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Kolory standardowe"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Kolory nocne"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Kolory niestandardowe"</string>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index 5d43efa..8f61478 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 44ecd41..8a727a1 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -425,7 +425,7 @@
     <string name="status_bar_airplane" msgid="7057575501472249002">"Modo de avião"</string>
     <string name="add_tile" msgid="2995389510240786221">"Adicionar mosaico"</string>
     <string name="broadcast_tile" msgid="3894036511763289383">"Mosaico de transmissão"</string>
-    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g> se desativar esta funcionalidade antes dessa hora"</string>
+    <string name="zen_alarm_warning_indef" msgid="3482966345578319605">"Só vai ouvir o próximo alarme (<xliff:g id="WHEN">%1$s</xliff:g>) se desativar esta funcionalidade antes dessa hora"</string>
     <string name="zen_alarm_warning" msgid="444533119582244293">"Não vai ouvir o próximo alarme às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template" msgid="3980063409350522735">"às <xliff:g id="WHEN">%1$s</xliff:g>"</string>
     <string name="alarm_template_far" msgid="4242179982586714810">"em <xliff:g id="WHEN">%1$s</xliff:g>"</string>
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar estas notificações sem som"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar no ecrã e emitir som"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Mais definições"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index 5d43efa..8f61478 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Mostrar essas notificações de forma silenciosa"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Mostrar na parte superior da lista de notificações e emitir som"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Mostrar parcialmente na tela e emitir som"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Mais configurações"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Concluído"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Cores normais"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Cores noturnas"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Cores personalizadas"</string>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index e9e7bdc..3ab8bf2 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -461,6 +461,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Aceste notificări se afișează fără a se emite un sunet"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Se afișează în partea de sus a listei cu notificări și se emite un sunet"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Se afișează pentru o scurtă durată pe ecran și se emite un sunet"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Mai multe setări"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Terminat"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Culori normale"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Culori de noapte"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Culori personalizate"</string>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index b68b434..6ffd333 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Показывать уведомления без звука."</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Показывать со звуком в начале списка уведомлений."</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Показывать со звуком поверх всех окон."</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Другие настройки"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Обычные цвета"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Ночные цвета"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Собственные цвета"</string>
diff --git a/packages/SystemUI/res/values-si-rLK/strings.xml b/packages/SystemUI/res/values-si-rLK/strings.xml
index b9f7e53..efbc042 100644
--- a/packages/SystemUI/res/values-si-rLK/strings.xml
+++ b/packages/SystemUI/res/values-si-rLK/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"නිශ්ශබ්දව මෙම දැනුම්දීම් පෙන්වන්න"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"දැනුම්දීම් ලැයිස්තුවෙහි ඉහළින්ම පෙන්වන්න සහ ශබ්ද කරන්න"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"තිරයට පැමිණ ශබ්ද කරන්න"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"තව සැකසීම්"</string>
+    <string name="notification_done" msgid="5279426047273930175">"නිමයි"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"සාමාන්‍ය වර්ණ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"රාත්‍රී වර්ණ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"අභිරුචි වර්ණ"</string>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 91a143e..31985b4 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Tieto upozornenia zobrazovať bez zvukového signálu"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Zobrazovať v hornej časti zoznamu upozornení so zvukovým signálom"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Zobrazovať cez obrazovku so zvukovým signálom"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Ďalšie nastavenia"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Hotovo"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normálne farby"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nočné farby"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Vlastné farby"</string>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index 96974ae..7c8d443 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Prikaži ta obvestila brez zvoka"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Prikaži na vrhu seznama obvestil in predvajaj zvok"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Za hip pokaži predogled na zaslonu in predvajaj zvok"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Več nastavitev"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Dokončano"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Običajne barve"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nočne barve"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Barve po meri"</string>
diff --git a/packages/SystemUI/res/values-sq-rAL/strings.xml b/packages/SystemUI/res/values-sq-rAL/strings.xml
index b904ae1..c8add94 100644
--- a/packages/SystemUI/res/values-sq-rAL/strings.xml
+++ b/packages/SystemUI/res/values-sq-rAL/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Shfaqi këto njoftime në heshtje"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Shfaqi në krye të listës së njoftimeve dhe lësho tingull"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Shfaq një vështrim të shpejtë në ekran dhe lësho tingull"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Cilësime të tjera"</string>
+    <string name="notification_done" msgid="5279426047273930175">"U krye"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Ngjyrat normale"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Ngjyrat e natës"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Ngjyrat e personalizuara"</string>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index 6470fcc..bec1fd4 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -455,12 +455,14 @@
     <string name="low_importance" msgid="4109929986107147930">"Мала важност"</string>
     <string name="default_importance" msgid="8192107689995742653">"Уобичајена важност"</string>
     <string name="high_importance" msgid="1527066195614050263">"Велика важност"</string>
-    <string name="max_importance" msgid="5089005872719563894">"Највећа важност"</string>
+    <string name="max_importance" msgid="5089005872719563894">"Важност: хитно"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"Ова обавештења се никада не приказују"</string>
     <string name="notification_importance_low" msgid="4383563267370859725">"Приказују се у дну листе обавештења без звука"</string>
     <string name="notification_importance_default" msgid="4926529615920610817">"Ова обавештења се приказују без звука"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Приказују се у врху листе обавештења и емитује се звук"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Накратко се приказују на екрану и емитује се звук"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Још подешавања"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Нормалне боје"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Ноћне боје"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Прилагођене боје"</string>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 5f2b397..d4a9cdc 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Visa aviseringarna utan ljud"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Visa högst upp på listan, med ljud"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Visa på skärmen, med ljud"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Fler inställningar"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Klar"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normala färger"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Nattfärger"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Anpassade färger"</string>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 8f962da..2ffbf2b 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Onyesha arifa hizi bila sauti"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Onyesha katika sehemu ya juu ya orodha ya arifa na itoe sauti"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Weka onyesho la kuchungulia kwenye skrini na itoe sauti"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Mipangilio zaidi"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Nimemaliza"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Rangi za kawaida"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Rangi za usiku"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Rangi maalum"</string>
diff --git a/packages/SystemUI/res/values-ta-rIN/strings.xml b/packages/SystemUI/res/values-ta-rIN/strings.xml
index a625c6f..168a11b 100644
--- a/packages/SystemUI/res/values-ta-rIN/strings.xml
+++ b/packages/SystemUI/res/values-ta-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ஒலியின்றி இந்த அறிவிப்புகளைக் காட்டு"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"அறிவிப்புகள் பட்டியலின் மேல் பகுதியில் ஒலியுடன் காட்டு"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"ஒலியுடன் திரையில் காட்டு"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"மேலும் அமைப்புகள்"</string>
+    <string name="notification_done" msgid="5279426047273930175">"முடிந்தது"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"இயல்பான வண்ணங்கள்"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"இரவுநேர வண்ணங்கள்"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"தனிப்பயன் வண்ணங்கள்"</string>
diff --git a/packages/SystemUI/res/values-te-rIN/strings.xml b/packages/SystemUI/res/values-te-rIN/strings.xml
index 9d1403f..086dede 100644
--- a/packages/SystemUI/res/values-te-rIN/strings.xml
+++ b/packages/SystemUI/res/values-te-rIN/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"ఈ నోటిఫికేషన్‌లను శబ్దం లేకుండా చూపుతుంది"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"నోటిఫికేషన్‌ల జాబితా ఎగువ భాగంలో శబ్దంతో చూపుతుంది"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"స్క్రీన్‌పై శీఘ్రంగా శబ్దంతో చూపుతుంది"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"మరిన్ని సెట్టింగ్‌లు"</string>
+    <string name="notification_done" msgid="5279426047273930175">"పూర్తయింది"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"సాధారణ రంగులు"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"రాత్రి రంగులు"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"అనుకూల రంగులు"</string>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 38e028c..8c1a7d3 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"แสดงการแจ้งเตือนเหล่านี้โดยไม่ส่งเสียง"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"แสดงที่ด้านบนของรายการแจ้งเตือนและส่งเสียง"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"แสดงบนหน้าจอในช่วงเวลาสั้นๆ และส่งเสียง"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"การตั้งค่าเพิ่มเติม"</string>
+    <string name="notification_done" msgid="5279426047273930175">"เสร็จสิ้น"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"สีปกติ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"สียามค่ำคืน"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"สีที่กำหนดเอง"</string>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 5815041..4bee3ea 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Tahimik na ipakita ang mga notification na ito"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Ipakita sa itaas ng listahan ng mga notification at mag-play ng tunog"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Ipasilip sa screen at mag-play ng tunog"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Higit pang mga setting"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Tapos Na"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Mga karaniwang kulay"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Madidilim na kulay"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Mga custom na kulay"</string>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index 6832808..c0ecc78 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirimleri sessizce göster"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Bildirim listesinin en üstünde göster ve ses çıkar"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Ekrana getir ve ses çıkar"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Diğer ayarlar"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Bitti"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Normal renkler"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Gece renkleri"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Özel renkler"</string>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index 9736028..3109403 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -462,6 +462,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Показувати ці сповіщення без звукового сигналу"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Показувати сповіщення вгорі списку зі звуковим сигналом"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Показувати сповіщення на екрані зі звуковим сигналом"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Більше налаштувань"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Готово"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Стандартні кольори"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Нічні кольори"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Користувацькі кольори"</string>
diff --git a/packages/SystemUI/res/values-ur-rPK/strings.xml b/packages/SystemUI/res/values-ur-rPK/strings.xml
index 28484eb..52aa580 100644
--- a/packages/SystemUI/res/values-ur-rPK/strings.xml
+++ b/packages/SystemUI/res/values-ur-rPK/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"خاموشی سے یہ اطلاعات دکھائیں"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"اطلاعات کی فہرست پر سب سے اوپر دکھائیں اور آواز چلائیں"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"اسکرین پر دکھائیں اور آواز چلائیں"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"مزید ترتیبات"</string>
+    <string name="notification_done" msgid="5279426047273930175">"ہوگیا"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"عام رنگ"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"رات کے رنگ"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"حسب ضرورت رنگ"</string>
diff --git a/packages/SystemUI/res/values-uz-rUZ/strings.xml b/packages/SystemUI/res/values-uz-rUZ/strings.xml
index 4bd9dbc..a849cfc 100644
--- a/packages/SystemUI/res/values-uz-rUZ/strings.xml
+++ b/packages/SystemUI/res/values-uz-rUZ/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Bu bildirishnomalar ovozsiz ko‘rsatilsin"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Bildirishnomalar ro‘yxatining boshida ovoz bilan ko‘rsatilsin"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Barcha oynalar ustida signal ovozi bilan ko‘rsatilsin"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Boshqa sozlamalar"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Tayyor"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Odatiy ranglar"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Qoramtir ranglar"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Foydalanuvchi rangi"</string>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index c094d5b..fa835ba 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Hiển thị im lặng các thông báo này"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Hiển thị ở đầu danh sách thông báo và phát ra âm thanh"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Hiển thị trên màn hình và phát ra âm thanh"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Cài đặt khác"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Xong"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Màu thông thường"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Màu tối"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Màu tùy chỉnh"</string>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index 3af77c2..bb8f4ad 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -460,6 +460,10 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"显示这些通知,但不发出提示音"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"在通知列表顶部显示,并发出提示音"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"在屏幕上持续显示,并发出提示音"</string>
+    <!-- no translation found for notification_more_settings (816306283396553571) -->
+    <skip />
+    <!-- no translation found for notification_done (5279426047273930175) -->
+    <skip />
     <string name="color_matrix_none" msgid="2121957926040543148">"常规颜色"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"夜间颜色"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"自定义颜色"</string>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index 8591785..0782354 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -454,12 +454,14 @@
     <string name="low_importance" msgid="4109929986107147930">"低重要性"</string>
     <string name="default_importance" msgid="8192107689995742653">"一般重要性"</string>
     <string name="high_importance" msgid="1527066195614050263">"高重要性"</string>
-    <string name="max_importance" msgid="5089005872719563894">"緊急"</string>
+    <string name="max_importance" msgid="5089005872719563894">"緊急重要性"</string>
     <string name="notification_importance_blocked" msgid="2397192642657872872">"永不顯示這些通知"</string>
     <string name="notification_importance_low" msgid="4383563267370859725">"顯示在通知清單底部但不發出音效"</string>
     <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知但不發出音效"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂部並發出音效"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"不時於螢幕出現並發出音效"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
+    <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"一般色系"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"深沉色系"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 34fa7aa..29520f6 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"顯示這些通知且不發出任何音效"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"顯示在通知清單頂端並發出音效"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"短暫顯示在螢幕上並發出音效"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"更多設定"</string>
+    <string name="notification_done" msgid="5279426047273930175">"完成"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"一般顏色"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"夜間顏色"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"自訂顏色"</string>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index ebd857c..3ee46ea 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -460,6 +460,8 @@
     <string name="notification_importance_default" msgid="4926529615920610817">"Bonisa ngokuthulile lezi zaziso"</string>
     <string name="notification_importance_high" msgid="3222680136612408223">"Bonisa ngaphezulu kohlu lwezaziso uphinde wenze umsindo"</string>
     <string name="notification_importance_max" msgid="5236987171904756134">"Bheka kusikrini uphinde wenze umsindo"</string>
+    <string name="notification_more_settings" msgid="816306283396553571">"Izilungiselelo eziningi"</string>
+    <string name="notification_done" msgid="5279426047273930175">"Kwenziwe"</string>
     <string name="color_matrix_none" msgid="2121957926040543148">"Imibala ejwayelekile"</string>
     <string name="color_matrix_night" msgid="5943817622105307072">"Imibala yasebusuku"</string>
     <string name="color_matrix_custom" msgid="3655576492322298713">"Imibala yangokwezifiso"</string>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 45ddd50..876c21e 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1228,6 +1228,11 @@
     <!-- [CHAR LIMIT=100] Notification Importance slider: max importance level description -->
     <string name="notification_importance_max">Peek onto the screen and make sound</string>
 
+    <!-- Notification: Control panel: Label for button that launches notification settings. [CHAR LIMIT=NONE] -->
+    <string name="notification_more_settings">More settings</string>
+    <!-- Notification: Control panel: Label for button that dismisses control panel. [CHAR LIMIT=NONE] -->
+    <string name="notification_done">Done</string>
+
     <!-- Label for no color transform [CHAR LIMIT=30] -->
     <string name="color_matrix_none">Normal colors</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 3b0ab791..527b638 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -317,4 +317,12 @@
         <item name="@dropdownPreferenceStyle">@style/Preference.DropDown.Material</item>
     </style>
 
+    <style name="TextAppearance.NotificationGuts">
+        <item name="android:textSize">14sp</item>
+        <item name="android:textColor">@color/notification_guts_btn_color</item>
+        <item name="android:textAllCaps">true</item>
+        <item name="android:fontFamily">sans-serif-medium</item>
+        <item name="android:gravity">center</item>
+    </style>
+
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
index b56ad76..01eb5f9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSIconView.java
@@ -75,7 +75,8 @@
             iv.setTag(R.id.qs_icon_tag, state.icon);
             if (d instanceof Animatable) {
                 Animatable a = (Animatable) d;
-                if (state.icon instanceof QSTile.AnimationIcon && !iv.isShown()) {
+                a.start();
+                if (!iv.isShown()) {
                     a.stop(); // skip directly to end state
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
index 39f0c55..1a36abd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSTile.java
@@ -19,8 +19,6 @@
 import android.app.PendingIntent;
 import android.content.Context;
 import android.content.Intent;
-import android.graphics.drawable.Animatable;
-import android.graphics.drawable.AnimatedVectorDrawable;
 import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.Looper;
@@ -29,9 +27,20 @@
 import android.util.SparseArray;
 import android.view.View;
 import android.view.ViewGroup;
-
 import com.android.systemui.qs.QSTile.State;
-import com.android.systemui.statusbar.policy.*;
+import com.android.systemui.statusbar.policy.BatteryController;
+import com.android.systemui.statusbar.policy.BluetoothController;
+import com.android.systemui.statusbar.policy.CastController;
+import com.android.systemui.statusbar.policy.FlashlightController;
+import com.android.systemui.statusbar.policy.HotspotController;
+import com.android.systemui.statusbar.policy.KeyguardMonitor;
+import com.android.systemui.statusbar.policy.Listenable;
+import com.android.systemui.statusbar.policy.LocationController;
+import com.android.systemui.statusbar.policy.NetworkController;
+import com.android.systemui.statusbar.policy.RotationLockController;
+import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.statusbar.policy.UserSwitcherController;
+import com.android.systemui.statusbar.policy.ZenModeController;
 
 import java.util.Collection;
 import java.util.Objects;
@@ -389,11 +398,7 @@
 
         @Override
         public Drawable getDrawable(Context context) {
-            Drawable d = context.getDrawable(mResId);
-            if (d instanceof Animatable) {
-                ((Animatable) d).start();
-            }
-            return d;
+            return context.getDrawable(mResId);
         }
 
         @Override
@@ -408,41 +413,14 @@
     }
 
     protected class AnimationIcon extends ResourceIcon {
-        private boolean mAllowAnimation;
-
         public AnimationIcon(int resId) {
             super(resId);
         }
 
-        public void setAllowAnimation(boolean allowAnimation) {
-            mAllowAnimation = allowAnimation;
-        }
-
         @Override
         public Drawable getDrawable(Context context) {
             // workaround: get a clean state for every new AVD
-            final AnimatedVectorDrawable d = (AnimatedVectorDrawable) context.getDrawable(mResId)
-                    .getConstantState().newDrawable();
-            d.start();
-            if (mAllowAnimation) {
-                mAllowAnimation = false;
-            } else {
-                d.stop(); // skip directly to end state
-            }
-            return d;
-        }
-    }
-
-    protected enum UserBoolean {
-        USER_TRUE(true, true),
-        USER_FALSE(true, false),
-        BACKGROUND_TRUE(false, true),
-        BACKGROUND_FALSE(false, false);
-        public final boolean value;
-        public final boolean userInitiated;
-        private UserBoolean(boolean userInitiated, boolean value) {
-            this.value = value;
-            this.userInitiated = userInitiated;
+            return context.getDrawable(mResId).getConstantState().newDrawable();
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
deleted file mode 100644
index a5e1fd5..0000000
--- a/packages/SystemUI/src/com/android/systemui/qs/QSTileServiceWrapper.java
+++ /dev/null
@@ -1,76 +0,0 @@
-package com.android.systemui.qs;
-
-import android.os.IBinder;
-import android.service.quicksettings.IQSTileService;
-import android.service.quicksettings.Tile;
-import android.util.Log;
-
-
-public class QSTileServiceWrapper implements IQSTileService {
-    private static final String TAG = "IQSTileServiceWrapper";
-
-    private final IQSTileService mService;
-    
-    public QSTileServiceWrapper(IQSTileService service) {
-        mService = service;
-    }
-
-    @Override
-    public IBinder asBinder() {
-        return mService.asBinder();
-    }
-
-    @Override
-    public void setQSTile(Tile tile) {
-        try {
-            mService.setQSTile(tile);
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onTileAdded() {
-        try {
-            mService.onTileAdded();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onTileRemoved() {
-        try {
-            mService.onTileRemoved();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onStartListening() {
-        try {
-            mService.onStartListening();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onStopListening() {
-        try {
-            mService.onStopListening();
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-
-    @Override
-    public void onClick(IBinder token) {
-        try {
-            mService.onClick(token);
-        } catch (Exception e) {
-            Log.d(TAG, "Caught exception from QSTileService", e);
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
index 87c2973..cdba3eb 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/CustomQSPanel.java
@@ -35,8 +35,8 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.QSTileServiceWrapper;
+import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.TunerService;
 
@@ -179,14 +179,16 @@
         mCurrentTiles.clear();
         for (int i = 0; i < mTiles.size(); i++) {
             if (mTiles.get(i).startsWith(CustomTile.PREFIX)) {
-                mCurrentTiles.add(BlankCustomTile.create(mHost, mTiles.get(i)));
+                QSTile<?> tile = BlankCustomTile.create(mHost, mTiles.get(i));
+                tile.setTileSpec(mTiles.get(i));
+                mCurrentTiles.add(tile);
             } else {
                 QSTile<?> tile = mHost.createTile(mTiles.get(i));
                 if (tile != null) {
+                    tile.setTileSpec(mTiles.get(i));
                     mCurrentTiles.add(tile);
                 }
             }
-            mCurrentTiles.get(mCurrentTiles.size() - 1).setTileSpec(mTiles.get(i));
         }
         super.setTiles(mCurrentTiles);
     }
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 6706c7a..a6a7143 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/customize/TileAdapter.java
@@ -41,7 +41,7 @@
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
 import com.android.systemui.qs.QSTile.Icon;
-import com.android.systemui.qs.tiles.CustomTile;
+import com.android.systemui.qs.external.CustomTile;
 import com.android.systemui.statusbar.phone.QSTileHost;
 import com.android.systemui.tuner.QSPagingSwitch;
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
similarity index 67%
rename from packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
rename to packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
index bb74f34..2e5a0b2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CustomTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/CustomTile.java
@@ -11,32 +11,26 @@
  * distributed under the License is distributed on an "AS IS" BASIS,
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
- * limitations under the License.
+ * limitations under the License
  */
+package com.android.systemui.qs.external;
 
-package com.android.systemui.qs.tiles;
-
-import android.app.ActivityManager;
-import android.app.Service;
 import android.content.ComponentName;
-import android.content.Intent;
-import android.content.ServiceConnection;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.graphics.drawable.Drawable;
 import android.os.Binder;
 import android.os.IBinder;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.service.quicksettings.IQSTileService;
 import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
 import android.util.Log;
 import android.view.IWindowManager;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.qs.QSTile;
-import com.android.systemui.qs.QSTileServiceWrapper;
 import com.android.systemui.statusbar.phone.QSTileHost;
 
 public class CustomTile extends QSTile<QSTile.State> {
@@ -52,8 +46,9 @@
     private final Tile mTile;
     private final IWindowManager mWindowManager;
     private final IBinder mToken = new Binder();
+    private final IQSTileService mService;
+    private final TileServiceManager mServiceManager;
 
-    private QSTileServiceWrapper mService;
     private boolean mListening;
     private boolean mBound;
     private boolean mIsTokenGranted;
@@ -63,7 +58,9 @@
         super(host);
         mWindowManager = WindowManagerGlobal.getWindowManagerService();
         mComponent = ComponentName.unflattenFromString(action);
-        mTile = new Tile(mComponent, host);
+        mServiceManager = host.getTileServices().getTileWrapper(this);
+        mService = mServiceManager.getTileService();
+        mTile = new Tile(mComponent);
         try {
             PackageManager pm = mContext.getPackageManager();
             ServiceInfo info = pm.getServiceInfo(mComponent, 0);
@@ -72,6 +69,11 @@
             mTile.setLabel(info.loadLabel(pm));
         } catch (Exception e) {
         }
+        try {
+            mService.setQSTile(mTile);
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
+        }
     }
 
     public ComponentName getComponent() {
@@ -96,42 +98,33 @@
     public void setListening(boolean listening) {
         if (mListening == listening) return;
         mListening = listening;
-        if (listening) {
-            mHandler.removeCallbacks(mUnbind);
-            if (!mBound) {
-                // TODO: Guarantee re-bind on user-switch.
-                mContext.bindServiceAsUser(new Intent().setComponent(mComponent),
-                        mServiceConnection, Service.BIND_AUTO_CREATE,
-                        new UserHandle(ActivityManager.getCurrentUser()));
-                mBound = true;
-            } else {
-                if (mService != null) {
+        try {
+            if (listening) {
+                if (mServiceManager.getType() == TileService.TILE_MODE_PASSIVE) {
+                    mServiceManager.setBindRequested(true);
                     mService.onStartListening();
-                } else {
-                    Log.d(TAG, "Can't start service listening");
                 }
-            }
-        } else {
-            if (mService != null) {
+            } else {
                 mService.onStopListening();
-            }
-            if (mIsTokenGranted && !mIsShowingDialog) {
-                try {
-                    if (DEBUG) Log.d(TAG, "Removing token");
-                    mWindowManager.removeWindowToken(mToken);
-                } catch (RemoteException e) {
+                if (mIsTokenGranted && !mIsShowingDialog) {
+                    try {
+                        if (DEBUG) Log.d(TAG, "Removing token");
+                        mWindowManager.removeWindowToken(mToken);
+                    } catch (RemoteException e) {
+                    }
+                    mIsTokenGranted = false;
                 }
-                mIsTokenGranted = false;
+                mIsShowingDialog = false;
+                mServiceManager.setBindRequested(false);
             }
-            mIsShowingDialog = false;
-            mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
         }
     }
 
     @Override
     protected void handleDestroy() {
         super.handleDestroy();
-        mHandler.removeCallbacks(mUnbind);
         if (mIsTokenGranted) {
             try {
                 if (DEBUG) Log.d(TAG, "Removing token");
@@ -139,7 +132,6 @@
             } catch (RemoteException e) {
             }
         }
-        mUnbind.run();
     }
 
     @Override
@@ -154,16 +146,20 @@
 
     @Override
     protected void handleClick() {
-        if (mService != null) {
-            try {
-                if (DEBUG) Log.d(TAG, "Adding token");
-                mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
-                mIsTokenGranted = true;
-            } catch (RemoteException e) {
+        try {
+            if (DEBUG) Log.d(TAG, "Adding token");
+            mWindowManager.addWindowToken(mToken, WindowManager.LayoutParams.TYPE_QS_DIALOG);
+            mIsTokenGranted = true;
+        } catch (RemoteException e) {
+        }
+        try {
+            if (mServiceManager.getType() == TileService.TILE_MODE_ACTIVE) {
+                mServiceManager.setBindRequested(true);
+                mService.onStartListening();
             }
             mService.onClick(mToken);
-        } else {
-            Log.e(TAG, "Click with no service " + getTileSpec());
+        } catch (RemoteException e) {
+            // Called through wrapper, won't happen here.
         }
         MetricsLogger.action(mContext, getMetricsCategory(), mComponent.getPackageName());
     }
@@ -187,34 +183,9 @@
 
     @Override
     public int getMetricsCategory() {
-        return MetricsLogger.QS_INTENT;
+        return MetricsLogger.QS_CUSTOM;
     }
 
-    private final ServiceConnection mServiceConnection = new ServiceConnection() {
-        @Override
-        public void onServiceConnected(ComponentName name, IBinder service) {
-            mService = new QSTileServiceWrapper(IQSTileService.Stub.asInterface(service));
-            if (mListening) {
-                mService.setQSTile(mTile);
-                mService.onStartListening();
-            } else {
-                mService.onStopListening();
-            }
-        }
-
-        @Override
-        public void onServiceDisconnected(ComponentName name) {
-        }
-    };
-
-    private final Runnable mUnbind = new Runnable() {
-        @Override
-        public void run() {
-            mContext.unbindService(mServiceConnection);
-            mBound = false;
-        }
-    };
-
     public static ComponentName getComponentFromSpec(String spec) {
         final String action = spec.substring(PREFIX.length(), spec.length() - 1);
         if (action.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
new file mode 100644
index 0000000..d41cdde
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/QSTileServiceWrapper.java
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.os.IBinder;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.util.Log;
+
+
+public class QSTileServiceWrapper {
+    private static final String TAG = "IQSTileServiceWrapper";
+
+    private final IQSTileService mService;
+
+    public QSTileServiceWrapper(IQSTileService service) {
+        mService = service;
+    }
+
+    public IBinder asBinder() {
+        return mService.asBinder();
+    }
+
+    public boolean setQSTile(Tile tile) {
+        try {
+            mService.setQSTile(tile);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onTileAdded() {
+        try {
+            mService.onTileAdded();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onTileRemoved() {
+        try {
+            mService.onTileRemoved();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onStartListening() {
+        try {
+            mService.onStartListening();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onStopListening() {
+        try {
+            mService.onStopListening();
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean onClick(IBinder token) {
+        try {
+            mService.onClick(token);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+
+    public boolean setQSService(IQSService service) {
+        try {
+            mService.setQSService(service);
+            return true;
+        } catch (Exception e) {
+            Log.d(TAG, "Caught exception from TileService", e);
+            return false;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
new file mode 100644
index 0000000..41fce9f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileLifecycleManager.java
@@ -0,0 +1,347 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.app.AppGlobals;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.ServiceConnection;
+import android.content.pm.PackageManager;
+import android.content.pm.ServiceInfo;
+import android.net.Uri;
+import android.os.Handler;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.support.annotation.VisibleForTesting;
+import android.util.ArraySet;
+import android.util.Log;
+import libcore.util.Objects;
+
+import java.util.Set;
+
+/**
+ * Manages the lifecycle of a TileService.
+ * <p>
+ * Will keep track of all calls on the IQSTileService interface and will relay those calls to the
+ * TileService as soon as it is bound.  It will only bind to the service when it is allowed to
+ * ({@link #setBindService(boolean)}) and when the service is available.
+ */
+public class TileLifecycleManager extends BroadcastReceiver implements
+        IQSTileService, ServiceConnection, IBinder.DeathRecipient {
+    public static final boolean DEBUG = false;
+
+    private static final String TAG = "TileLifecycleManager";
+
+    private static final int MSG_ON_ADDED = 0;
+    private static final int MSG_ON_REMOVED = 1;
+    private static final int MSG_ON_CLICK = 2;
+
+    // Bind retry control.
+    private static final int MAX_BIND_RETRIES = 5;
+    private static final int BIND_RETRY_DELAY = 1000;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final Intent mIntent;
+    private final UserHandle mUser;
+
+    private Set<Integer> mQueuedMessages = new ArraySet<>();
+    private QSTileServiceWrapper mWrapper;
+    private boolean mListening;
+    private Tile mTile;
+    private IBinder mClickBinder;
+
+    private int mBindTryCount;
+    private boolean mBound;
+    @VisibleForTesting
+    boolean mReceiverRegistered;
+    private IQSService mService;
+
+    public TileLifecycleManager(Handler handler, Context context, Intent intent, UserHandle user) {
+        mContext = context;
+        mHandler = handler;
+        mIntent = intent;
+        mUser = user;
+    }
+
+    public ComponentName getComponent() {
+        return mIntent.getComponent();
+    }
+
+    public boolean hasPendingClick() {
+        synchronized (mQueuedMessages) {
+            return mQueuedMessages.contains(MSG_ON_CLICK);
+        }
+    }
+
+    public void setBindService(boolean bind) {
+        mBound = bind;
+        if (bind) {
+            if (mBindTryCount == MAX_BIND_RETRIES) {
+                // Too many failures, give up on this tile until an update.
+                startPackageListening();
+                return;
+            }
+            if (!checkComponentState()) {
+                return;
+            }
+            if (DEBUG) Log.d(TAG, "Binding service " + mIntent);
+            mBindTryCount++;
+            mContext.bindServiceAsUser(mIntent, this,
+                    Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE_WHILE_AWAKE,
+                    mUser);
+        } else {
+            if (DEBUG) Log.d(TAG, "Unbinding service " + mIntent);
+            // Give it another chance next time it needs to be bound, out of kindness.
+            mBindTryCount = 0;
+            mWrapper = null;
+            mContext.unbindService(this);
+        }
+    }
+
+    @Override
+    public void onServiceConnected(ComponentName name, IBinder service) {
+        if (DEBUG) Log.d(TAG, "onServiceConnected " + name);
+        // Got a connection, set the binding count to 0.
+        mBindTryCount = 0;
+        mWrapper = new QSTileServiceWrapper(Stub.asInterface(service));
+        try {
+            service.linkToDeath(this, 0);
+        } catch (RemoteException e) {
+        }
+        setQSService(mService);
+        setQSTile(mTile);
+        handlePendingMessages();
+    }
+
+    @Override
+    public void onServiceDisconnected(ComponentName name) {
+        if (DEBUG) Log.d(TAG, "onServiceDisconnected " + name);
+        mWrapper = null;
+    }
+
+    private void handlePendingMessages() {
+        // This ordering is laid out manually to make sure we preserve the TileService
+        // lifecycle.
+        ArraySet<Integer> queue;
+        synchronized (mQueuedMessages) {
+            queue = new ArraySet<>(mQueuedMessages);
+            mQueuedMessages.clear();
+        }
+        if (queue.contains(MSG_ON_ADDED)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onAdded");
+            onTileAdded();
+        }
+        if (mListening) {
+            if (DEBUG) Log.d(TAG, "Handling pending onStartListening");
+            onStartListening();
+        }
+        if (queue.contains(MSG_ON_CLICK)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onClick");
+            if (!mListening) {
+                Log.w(TAG, "Managed to get click on non-listening state...");
+                // Skipping click since lost click privileges.
+            } else {
+                onClick(mClickBinder);
+            }
+        }
+        if (queue.contains(MSG_ON_REMOVED)) {
+            if (DEBUG) Log.d(TAG, "Handling pending onRemoved");
+            if (mListening) {
+                Log.w(TAG, "Managed to get remove in listening state...");
+                onStopListening();
+            }
+            onTileRemoved();
+        }
+    }
+
+    public void handleDestroy() {
+        if (DEBUG) Log.d(TAG, "handleDestroy");
+        if (mReceiverRegistered) {
+            stopPackageListening();
+        }
+    }
+
+    private void handleDeath() {
+        if (mWrapper == null) return;
+        mWrapper = null;
+        if (!mBound) return;
+        if (DEBUG) Log.d(TAG, "handleDeath");
+        if (checkComponentState()) {
+            mHandler.postDelayed(new Runnable() {
+                @Override
+                public void run() {
+                    if (mBound) {
+                        // Retry binding.
+                        setBindService(true);
+                    }
+                }
+            }, BIND_RETRY_DELAY);
+        }
+    }
+
+    @Override
+    public void setQSTile(Tile tile) {
+        if (DEBUG) Log.d(TAG, "setQSTile " + tile);
+        mTile = tile;
+        if (mWrapper != null && !mWrapper.setQSTile(tile)) {
+            handleDeath();
+        }
+    }
+
+    private boolean checkComponentState() {
+        PackageManager pm = mContext.getPackageManager();
+        if (!isPackageAvailable(pm) || !isComponentAvailable(pm)) {
+            startPackageListening();
+            return false;
+        }
+        return true;
+    }
+
+    private void startPackageListening() {
+        if (DEBUG) Log.d(TAG, "startPackageListening");
+        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);
+        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
+        filter.addDataScheme("package");
+        mContext.registerReceiverAsUser(this, mUser, filter, null, mHandler);
+        mReceiverRegistered = true;
+    }
+
+    private void stopPackageListening() {
+        if (DEBUG) Log.d(TAG, "stopPackageListening");
+        mContext.unregisterReceiver(this);
+        mReceiverRegistered = false;
+    }
+
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        if (DEBUG) Log.d(TAG, "onReceive: " + intent);
+        Uri data = intent.getData();
+        String pkgName = data.getEncodedSchemeSpecificPart();
+        if (!Objects.equal(pkgName, mIntent.getComponent().getPackageName())) {
+            return;
+        }
+        stopPackageListening();
+        if (mBound) {
+            // Trying to bind again will check the state of the package before bothering to bind.
+            if (DEBUG) Log.d(TAG, "Trying to rebind");
+            setBindService(true);
+        }
+    }
+
+    private boolean isComponentAvailable(PackageManager pm) {
+        String packageName = mIntent.getComponent().getPackageName();
+        try {
+            ServiceInfo si = AppGlobals.getPackageManager().getServiceInfo(mIntent.getComponent(),
+                    0, mUser.getIdentifier());
+            if (DEBUG && si == null) Log.d(TAG, "Can't find component " + mIntent.getComponent());
+            return si != null;
+        } catch (RemoteException e) {
+            // Shouldn't happen.
+        }
+        return false;
+    }
+
+    private boolean isPackageAvailable(PackageManager pm) {
+        String packageName = mIntent.getComponent().getPackageName();
+        try {
+            pm.getPackageInfoAsUser(packageName, 0, mUser.getIdentifier());
+            return true;
+        } catch (PackageManager.NameNotFoundException e) {
+            if (DEBUG) Log.d(TAG, "Package not available: " + packageName, e);
+            else Log.d(TAG, "Package not available: " + packageName);
+        }
+        return false;
+    }
+
+    private void queueMessage(int message) {
+        synchronized (mQueuedMessages) {
+            mQueuedMessages.add(message);
+        }
+    }
+
+    @Override
+    public void setQSService(IQSService service) {
+        mService = service;
+        if (mWrapper == null || !mWrapper.setQSService(service)) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onTileAdded() {
+        if (DEBUG) Log.d(TAG, "onTileAdded");
+        if (mWrapper == null || !mWrapper.onTileAdded()) {
+            queueMessage(MSG_ON_ADDED);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onTileRemoved() {
+        if (DEBUG) Log.d(TAG, "onTileRemoved");
+        if (mWrapper == null || !mWrapper.onTileRemoved()) {
+            queueMessage(MSG_ON_REMOVED);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onStartListening() {
+        if (DEBUG) Log.d(TAG, "onStartListening");
+        mListening = true;
+        if (mWrapper != null && !mWrapper.onStartListening()) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onStopListening() {
+        if (DEBUG) Log.d(TAG, "onStopListening");
+        mListening = false;
+        if (mWrapper != null && !mWrapper.onStopListening()) {
+            handleDeath();
+        }
+    }
+
+    @Override
+    public void onClick(IBinder iBinder) {
+        if (DEBUG) Log.d(TAG, "onClick " + iBinder);
+        if (mWrapper == null || !mWrapper.onClick(iBinder)) {
+            mClickBinder = iBinder;
+            queueMessage(MSG_ON_CLICK);
+            handleDeath();
+        }
+    }
+
+    @Override
+    public IBinder asBinder() {
+        return mWrapper != null ? mWrapper.asBinder() : null;
+    }
+
+    @Override
+    public void binderDied() {
+        if (DEBUG) Log.d(TAG, "binderDeath");
+        handleDeath();
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
new file mode 100644
index 0000000..2f77a30
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServiceManager.java
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.app.ActivityManager;
+import android.content.ComponentName;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.TileService;
+import android.support.annotation.VisibleForTesting;
+import android.util.Log;
+
+/**
+ * Manages the priority which lets {@link TileServices} make decisions about which tiles
+ * to bind.  Also holds on to and manages the {@link TileLifecycleManager}, informing it
+ * of when it is allowed to bind based on decisions frome the {@link TileServices}.
+ */
+public class TileServiceManager {
+
+    private static final long MIN_BIND_TIME = 5000;
+    private static final long UNBIND_DELAY = 30000;
+
+    public static final boolean DEBUG = true;
+
+    private static final String TAG = "TileServiceManager";
+
+    @VisibleForTesting
+    static final String PREFS_FILE = "CustomTileModes";
+
+    private final TileServices mServices;
+    private final TileLifecycleManager mStateManager;
+    private final Handler mHandler;
+    private boolean mBindRequested;
+    private boolean mBindAllowed;
+    private boolean mBound;
+    private int mPriority;
+    private boolean mJustBound;
+    private long mLastUpdate;
+    private int mType;
+
+    TileServiceManager(TileServices tileServices, Handler handler, ComponentName component) {
+        this(tileServices, handler, new TileLifecycleManager(handler,
+                tileServices.getContext(), new Intent().setComponent(component),
+                new UserHandle(ActivityManager.getCurrentUser())));
+    }
+
+    @VisibleForTesting
+    TileServiceManager(TileServices tileServices, Handler handler,
+            TileLifecycleManager tileLifecycleManager) {
+        mServices = tileServices;
+        mHandler = handler;
+        mStateManager = tileLifecycleManager;
+        mType = tileServices.getContext().getSharedPreferences(PREFS_FILE, 0)
+                .getInt(tileLifecycleManager.getComponent().flattenToString(),
+                        TileService.TILE_MODE_UNSET);
+        mStateManager.setQSService(tileServices);
+        if (mType == TileService.TILE_MODE_UNSET) {
+            bindService();
+            mStateManager.onTileAdded();
+        }
+    }
+
+    public int getType() {
+        return mType;
+    }
+
+    public void setType(int type) {
+        mServices.getContext().getSharedPreferences(PREFS_FILE, 0).edit()
+                .putInt(mStateManager.getComponent().flattenToString(), type).commit();
+        mType = type;
+        mServices.recalculateBindAllowance();
+    }
+
+    public IQSTileService getTileService() {
+        return mStateManager;
+    }
+
+    public void setBindRequested(boolean bindRequested) {
+        if (mBindRequested == bindRequested) return;
+        mBindRequested = bindRequested;
+        if (mBindAllowed && mBindRequested && !mBound) {
+            mHandler.removeCallbacks(mUnbind);
+            bindService();
+        } else {
+            mServices.recalculateBindAllowance();
+        }
+        if (mBound && !mBindRequested) {
+            mHandler.postDelayed(mUnbind, UNBIND_DELAY);
+        }
+    }
+
+    public void setLastUpdate(long lastUpdate) {
+        mLastUpdate = lastUpdate;
+        if (mBound && mType == TileService.TILE_MODE_ACTIVE) {
+            mStateManager.onStopListening();
+            setBindRequested(false);
+        }
+        mServices.recalculateBindAllowance();
+    }
+
+    public void handleDestroy() {
+        mStateManager.handleDestroy();
+    }
+
+    public void setBindAllowed(boolean allowed) {
+        if (mBindAllowed == allowed) return;
+        mBindAllowed = allowed;
+        if (!mBindAllowed && mBound) {
+            unbindService();
+        } else if (mBindAllowed && mBindRequested && !mBound) {
+            bindService();
+        }
+    }
+
+    private void bindService() {
+        if (mBound) {
+            Log.e(TAG, "Service already bound");
+            return;
+        }
+        mBound = true;
+        mJustBound = true;
+        mHandler.postDelayed(mJustBoundOver, MIN_BIND_TIME);
+        mStateManager.setBindService(true);
+    }
+
+    private void unbindService() {
+        if (!mBound) {
+            Log.e(TAG, "Service not bound");
+            return;
+        }
+        mBound = false;
+        mJustBound = false;
+        mStateManager.setBindService(false);
+    }
+
+    public void calculateBindPriority(long currentTime) {
+        if (mStateManager.hasPendingClick()) {
+            // Pending click is the most important thing, need to put this service at the top of
+            // the list to be bound.
+            mPriority = Integer.MAX_VALUE;
+        } else if (mJustBound) {
+            // If we just bound, lets not thrash on binding/unbinding too much, this is second most
+            // important.
+            mPriority = Integer.MAX_VALUE - 1;
+        } else if (!mBindRequested) {
+            // Don't care about binding right now, put us last.
+            mPriority = Integer.MIN_VALUE;
+        } else {
+            // Order based on whether this was just updated.
+            long timeSinceUpdate = currentTime - mLastUpdate;
+            // Fit compare into integer space for simplicity. Make sure to leave MAX_VALUE and
+            // MAX_VALUE - 1 for the more important states above.
+            if (timeSinceUpdate > Integer.MAX_VALUE - 2) {
+                mPriority = Integer.MAX_VALUE - 2;
+            } else {
+                mPriority = (int) timeSinceUpdate;
+            }
+        }
+    }
+
+    public int getBindPriority() {
+        return mPriority;
+    }
+
+    private final Runnable mUnbind = new Runnable() {
+        @Override
+        public void run() {
+            if (mBound && !mBindRequested) {
+                unbindService();
+            }
+        }
+    };
+
+    @VisibleForTesting
+    final Runnable mJustBoundOver = new Runnable() {
+        @Override
+        public void run() {
+            mJustBound = false;
+            mServices.recalculateBindAllowance();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
new file mode 100644
index 0000000..00f7699
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/external/TileServices.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Binder;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.Tile;
+import android.service.quicksettings.TileService;
+import android.util.ArrayMap;
+import android.util.Log;
+import com.android.systemui.statusbar.phone.QSTileHost;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+
+/**
+ * Runs the day-to-day operations of which tiles should be bound and when.
+ */
+public class TileServices extends IQSService.Stub {
+    static final int DEFAULT_MAX_BOUND = 3;
+    static final int REDUCED_MAX_BOUND = 1;
+
+    private final ArrayMap<CustomTile, TileServiceManager> mServices = new ArrayMap<>();
+    private final ArrayMap<ComponentName, CustomTile> mTiles = new ArrayMap<>();
+    private final Context mContext;
+    private final Handler mHandler;
+    private final QSTileHost mHost;
+
+    private int mMaxBound = DEFAULT_MAX_BOUND;
+
+    public TileServices(QSTileHost host, Looper looper) {
+        mHost = host;
+        mContext = mHost.getContext();
+        mContext.registerReceiver(mRequestListeningReceiver,
+                new IntentFilter(TileService.ACTION_REQUEST_LISTENING));
+        mHandler = new Handler(looper);
+    }
+
+    public Context getContext() {
+        return mContext;
+    }
+
+    public TileServiceManager getTileWrapper(CustomTile tile) {
+        ComponentName component = tile.getComponent();
+        TileServiceManager service = onCreateTileService(component);
+        synchronized (mServices) {
+            mServices.put(tile, service);
+            mTiles.put(component, tile);
+        }
+        return service;
+    }
+
+    protected TileServiceManager onCreateTileService(ComponentName component) {
+        return new TileServiceManager(this, mHandler, component);
+    }
+
+    public void freeService(CustomTile tile, TileServiceManager service) {
+        synchronized (mServices) {
+            service.setBindAllowed(false);
+            mServices.remove(tile);
+            mTiles.remove(tile.getComponent());
+        }
+    }
+
+    public void setMemoryPressure(boolean memoryPressure) {
+        mMaxBound = memoryPressure ? REDUCED_MAX_BOUND : DEFAULT_MAX_BOUND;
+        recalculateBindAllowance();
+    }
+
+    public void recalculateBindAllowance() {
+        final ArrayList<TileServiceManager> services;
+        synchronized (mServices) {
+            services = new ArrayList<>(mServices.values());
+        }
+        final int N = services.size();
+        if (N > mMaxBound) {
+            long currentTime = System.currentTimeMillis();
+            // Precalculate the priority of services for binding.
+            for (int i = 0; i < N; i++) {
+                services.get(i).calculateBindPriority(currentTime);
+            }
+            // Sort them so we can bind the most important first.
+            Collections.sort(services, SERVICE_SORT);
+        }
+        int i;
+        // Allow mMaxBound items to bind.
+        for (i = 0; i < mMaxBound && i < N; i++) {
+            services.get(i).setBindAllowed(true);
+        }
+        // The rest aren't allowed to bind for now.
+        while (i < N) {
+            services.get(i).setBindAllowed(false);
+            i++;
+        }
+    }
+
+    private void verifyCaller(String packageName) {
+        try {
+            int uid = mContext.getPackageManager().getPackageUid(packageName,
+                    Binder.getCallingUserHandle().getIdentifier());
+            if (Binder.getCallingUid() != uid) {
+                throw new SecurityException("Component outside caller's uid");
+            }
+        } catch (PackageManager.NameNotFoundException e) {
+            throw new SecurityException(e);
+        }
+    }
+
+    private void requestListening(ComponentName component) {
+        synchronized (mServices) {
+            CustomTile customTile = getTileForComponent(component);
+            if (customTile == null) {
+                Log.d("TileServices", "Couldn't find tile for " + component);
+                return;
+            }
+            TileServiceManager service = mServices.get(customTile);
+            if (service.getType() != TileService.TILE_MODE_ACTIVE) {
+                return;
+            }
+            service.setBindRequested(true);
+            try {
+                service.getTileService().onStartListening();
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    @Override
+    public void setTileMode(ComponentName component, int mode) {
+        verifyCaller(component.getPackageName());
+        CustomTile customTile = getTileForComponent(component);
+        if (customTile != null) {
+            synchronized (mServices) {
+                mServices.get(customTile).setType(mode);
+            }
+        }
+    }
+
+    @Override
+    public void updateQsTile(Tile tile) {
+        verifyCaller(tile.getComponentName().getPackageName());
+        CustomTile customTile = getTileForComponent(tile.getComponentName());
+        if (customTile != null) {
+            synchronized (mServices) {
+                mServices.get(customTile).setLastUpdate(System.currentTimeMillis());
+            }
+            customTile.updateState(tile);
+            customTile.refreshState();
+        }
+    }
+
+    @Override
+    public void onShowDialog(Tile tile) {
+        verifyCaller(tile.getComponentName().getPackageName());
+        CustomTile customTile = getTileForComponent(tile.getComponentName());
+        if (customTile != null) {
+            customTile.onDialogShown();
+            mHost.collapsePanels();
+        }
+    }
+
+    private CustomTile getTileForComponent(ComponentName component) {
+        synchronized (mServices) {
+            return mTiles.get(component);
+        }
+    }
+
+    private final BroadcastReceiver mRequestListeningReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (TileService.ACTION_REQUEST_LISTENING.equals(intent.getAction())) {
+                requestListening(
+                        (ComponentName) intent.getParcelableExtra(TileService.EXTRA_COMPONENT));
+            }
+        }
+    };
+
+    private static final Comparator<TileServiceManager> SERVICE_SORT =
+            new Comparator<TileServiceManager>() {
+        @Override
+        public int compare(TileServiceManager left, TileServiceManager right) {
+            return -Integer.compare(left.getBindPriority(), right.getBindPriority());
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
index fc802dd..c696f88 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/AirplaneModeTile.java
@@ -58,8 +58,6 @@
     public void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         setEnabled(!mState.value);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     private void setEnabled(boolean enabled) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
index f73ee35..23a15b9 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/ColorInversionTile.java
@@ -71,8 +71,6 @@
     protected void handleClick() {
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         mSetting.setValue(mState.value ? 0 : 1);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
index d96f735..4f9f46d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/DndTile.java
@@ -107,8 +107,6 @@
                     Toast.LENGTH_LONG).show();
             return;
         }
-        mDisable.setAllowAnimation(true);
-        mDisableTotalSilence.setAllowAnimation(true);
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         if (mState.value) {
             mController.setZen(Global.ZEN_MODE_OFF, null, TAG);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
index 12c1298..39d9da1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/FlashlightTile.java
@@ -64,7 +64,7 @@
         }
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         boolean newState = !mState.value;
-        refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+        refreshState(newState);
         mFlashlightController.setFlashlight(newState);
     }
 
@@ -73,8 +73,8 @@
         // TODO: Flashlight available handling...
 //        state.visible = mFlashlightController.isAvailable();
         state.label = mHost.getContext().getString(R.string.quick_settings_flashlight_label);
-        if (arg instanceof UserBoolean) {
-            boolean value = ((UserBoolean) arg).value;
+        if (arg instanceof Boolean) {
+            boolean value = (Boolean) arg;
             if (value == state.value) {
                 return;
             }
@@ -83,7 +83,6 @@
             state.value = mFlashlightController.isEnabled();
         }
         final AnimationIcon icon = state.value ? mEnable : mDisable;
-        icon.setAllowAnimation(arg instanceof UserBoolean && ((UserBoolean) arg).userInitiated);
         state.icon = icon;
         int onOrOffId = state.value
                 ? R.string.accessibility_quick_settings_flashlight_on
@@ -107,12 +106,12 @@
 
     @Override
     public void onFlashlightChanged(boolean enabled) {
-        refreshState(enabled ? UserBoolean.BACKGROUND_TRUE : UserBoolean.BACKGROUND_FALSE);
+        refreshState(enabled);
     }
 
     @Override
     public void onFlashlightError() {
-        refreshState(UserBoolean.BACKGROUND_FALSE);
+        refreshState(false);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
index 250d567..55aa32b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/HotspotTile.java
@@ -59,8 +59,6 @@
         final boolean isEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !isEnabled);
         mController.setHotspotEnabled(!isEnabled);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
index 08540f6..e79aabf 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/LocationTile.java
@@ -67,8 +67,6 @@
                     mHost.openPanels();
                     MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
                     mController.setLocationEnabled(!wasEnabled);
-                    mEnable.setAllowAnimation(true);
-                    mDisable.setAllowAnimation(true);
                 }
             });
             return;
@@ -76,8 +74,6 @@
         final boolean wasEnabled = (Boolean) mState.value;
         MetricsLogger.action(mContext, getMetricsCategory(), !wasEnabled);
         mController.setLocationEnabled(!wasEnabled);
-        mEnable.setAllowAnimation(true);
-        mDisable.setAllowAnimation(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
index d85cf60..7bce54b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/RotationLockTile.java
@@ -63,15 +63,14 @@
         MetricsLogger.action(mContext, getMetricsCategory(), !mState.value);
         final boolean newState = !mState.value;
         mController.setRotationLocked(newState);
-        refreshState(newState ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
+        refreshState(newState);
     }
 
     @Override
     protected void handleUpdateState(BooleanState state, Object arg) {
         if (mController == null) return;
-        final boolean rotationLocked = arg != null ? ((UserBoolean) arg).value
+        final boolean rotationLocked = arg != null ? (Boolean) arg
                 : mController.isRotationLocked();
-        final boolean userInitiated = arg != null ? ((UserBoolean) arg).userInitiated : false;
         // TODO: Handle accessibility rotation lock and whatnot.
 //        state.visible = mController.isRotationLockAffordanceVisible();
         if (state.value == rotationLocked && state.contentDescription != null) {
@@ -80,18 +79,15 @@
         }
         state.value = rotationLocked;
         final boolean portrait = isCurrentOrientationLockPortrait();
-        final AnimationIcon icon;
         if (rotationLocked) {
             final int label = portrait ? R.string.quick_settings_rotation_locked_portrait_label
                     : R.string.quick_settings_rotation_locked_landscape_label;
             state.label = mContext.getString(label);
-            icon = portrait ? mAutoToPortrait : mAutoToLandscape;
+            state.icon = portrait ? mAutoToPortrait : mAutoToLandscape;
         } else {
             state.label = mContext.getString(R.string.quick_settings_rotation_unlocked_label);
-            icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
+            state.icon = portrait ? mPortraitToAuto : mLandscapeToAuto;
         }
-        icon.setAllowAnimation(userInitiated);
-        state.icon = icon;
         state.contentDescription = getAccessibilityString(rotationLocked,
                 R.string.accessibility_rotation_lock_on_portrait,
                 R.string.accessibility_rotation_lock_on_landscape,
@@ -145,8 +141,7 @@
     private final RotationLockControllerCallback mCallback = new RotationLockControllerCallback() {
         @Override
         public void onRotationLockStateChanged(boolean rotationLocked, boolean affordanceVisible) {
-            refreshState(rotationLocked ? UserBoolean.BACKGROUND_TRUE
-                    : UserBoolean.BACKGROUND_FALSE);
+            refreshState(rotationLocked);
         }
     };
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
index 07915f8..255f29f 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WorkModeTile.java
@@ -93,12 +93,7 @@
     }
 
     private void refreshQuietModeState(boolean backgroundRefresh) {
-        if (backgroundRefresh) {
-            refreshState(isWorkModeEnabled() ? UserBoolean.BACKGROUND_TRUE
-                    : UserBoolean.BACKGROUND_FALSE);
-        } else {
-            refreshState(isWorkModeEnabled() ? UserBoolean.USER_TRUE : UserBoolean.USER_FALSE);
-        }
+        refreshState(isWorkModeEnabled());
     }
 
     @Override
@@ -108,28 +103,22 @@
             return;
         }
 
-        final boolean userInitialized;
-        if (arg instanceof UserBoolean) {
-            state.value = ((UserBoolean) arg).value;
-            userInitialized = ((UserBoolean) arg).userInitiated;
+        if (arg instanceof Boolean) {
+            state.value = (Boolean) arg;
         } else {
             state.value = isWorkModeEnabled();
-            userInitialized = false;
         }
 
-        final AnimationIcon icon;
         state.label = mContext.getString(R.string.quick_settings_work_mode_label);
         if (state.value) {
-            icon = mEnable;
+            state.icon = mEnable;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_on);
         } else {
-            icon = mDisable;
+            state.icon = mDisable;
             state.contentDescription =  mContext.getString(
                     R.string.accessibility_quick_settings_work_mode_off);
         }
-        icon.setAllowAnimation(userInitialized);
-        state.icon = icon;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index ffcc805..57074df 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -77,6 +77,7 @@
 import com.android.systemui.recents.views.RecentsView;
 import com.android.systemui.recents.views.SystemBarScrimViews;
 import com.android.systemui.recents.views.ViewAnimation;
+import com.android.systemui.statusbar.BaseStatusBar;
 
 import java.util.ArrayList;
 
@@ -298,12 +299,23 @@
      */
     void dismissRecentsToHome(boolean animated) {
         if (animated) {
-            ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger(null,
-                    mFinishLaunchHomeRunnable, null);
+            ReferenceCountedTrigger exitTrigger = new ReferenceCountedTrigger();
+            exitTrigger.increment();
+            exitTrigger.addLastDecrementRunnable(mFinishLaunchHomeRunnable);
+            exitTrigger.addLastDecrementRunnable(new Runnable() {
+                @Override
+                public void run() {
+                    Recents.getSystemServices().sendCloseSystemWindows(
+                            BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
+                }
+            });
             mRecentsView.startExitToHomeAnimation(
                     new ViewAnimation.TaskViewExitContext(exitTrigger));
+            exitTrigger.decrement();
         } else {
             mFinishLaunchHomeRunnable.run();
+            Recents.getSystemServices().sendCloseSystemWindows(
+                    BaseStatusBar.SYSTEM_DIALOG_REASON_HOME_KEY);
         }
     }
 
@@ -343,7 +355,7 @@
         EventBus.getDefault().register(this, EVENT_BUS_PRIORITY);
 
         // Initialize the widget host (the host id is static and does not change)
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             mAppWidgetHost = new RecentsAppWidgetHost(this, RecentsAppWidgetHost.HOST_ID);
         }
         mPackageMonitor = new RecentsPackageMonitor();
@@ -368,14 +380,14 @@
         mFinishLaunchHomeRunnable = new FinishRecentsRunnable(homeIntent);
 
         // Bind the search app widget when we first start up
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             mSearchWidgetInfo = ssp.getOrBindSearchAppWidget(this, mAppWidgetHost);
         }
 
         // Register the broadcast receiver to handle messages when the screen is turned off
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_SCREEN_OFF);
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             filter.addAction(SearchManager.INTENT_GLOBAL_SEARCH_ACTIVITY_CHANGED);
         }
         registerReceiver(mSystemBroadcastReceiver, filter);
@@ -475,7 +487,7 @@
         mPackageMonitor.unregister();
 
         // Stop listening for widget package changes if there was one bound
-        if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
             mAppWidgetHost.stopListening();
         }
 
@@ -656,8 +668,8 @@
         ReferenceCountedTrigger t = new ReferenceCountedTrigger();
         ViewAnimation.TaskViewEnterContext ctx = new ViewAnimation.TaskViewEnterContext(t);
         ctx.postAnimationTrigger.increment();
-        if (mSearchWidgetInfo != null) {
-            if (!RecentsDebugFlags.Static.DisableSearchBar) {
+        if (RecentsDebugFlags.Static.EnableSearchBar) {
+            if (mSearchWidgetInfo != null) {
                 ctx.postAnimationTrigger.addLastDecrementRunnable(new Runnable() {
                     @Override
                     public void run() {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 7547570f..cfbd1cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -74,9 +74,6 @@
     public int svelteLevel;
     public int searchBarSpaceHeightPx;
 
-    /** Dev options and global settings */
-    public boolean lockToAppEnabled;
-
     public RecentsConfiguration(Context context) {
         // Load only resources that can not change after the first load either through developer
         // settings or via multi window
@@ -106,12 +103,7 @@
     /**
      * Updates the configuration based on the current state of the system
      */
-    void update(Context context, SystemServicesProxy ssp, Rect windowRect) {
-        // Only update resources that can change after the first load, either through developer
-        // settings or via multi window
-        lockToAppEnabled = !ssp.hasFreeformWorkspaceSupport() &&
-                ssp.getSystemSetting(context, Settings.System.LOCK_TO_APP_ENABLED) != 0;
-
+    void update(Rect windowRect) {
         // Recompute some values based on the given state, since we can not rely on the resource
         // system to get certain values.
         boolean isLandscape = windowRect.width() > windowRect.height();
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
index 40c84ba..c323522 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsDebugFlags.java
@@ -32,8 +32,8 @@
     public static class Static {
         // Enables debug drawing for the transition thumbnail
         public static final boolean EnableTransitionThumbnailDebugMode = false;
-        // This disables the search bar integration
-        public static final boolean DisableSearchBar = true;
+        // This enables the search bar integration
+        public static final boolean EnableSearchBar = false;
         // This disables the bitmap and icon caches
         public static final boolean DisableBackgroundCache = false;
         // Enables the simulated task affiliations
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 949fb86..fd00289 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -19,6 +19,7 @@
 import android.app.ActivityManager;
 import android.app.ActivityOptions;
 import android.app.ITaskStackListener;
+import android.appwidget.AppWidgetProviderInfo;
 import android.content.ActivityNotFoundException;
 import android.content.Context;
 import android.content.Intent;
@@ -60,6 +61,7 @@
 import com.android.systemui.recents.views.TaskStackView;
 import com.android.systemui.recents.views.TaskViewHeader;
 import com.android.systemui.recents.views.TaskViewTransform;
+import com.android.systemui.statusbar.BaseStatusBar;
 import com.android.systemui.statusbar.phone.PhoneStatusBar;
 
 import java.util.ArrayList;
@@ -104,6 +106,10 @@
             mHandler.post(this);
         }
 
+        @Override
+        public void onActivityPinned() {
+        }
+
         /** Preloads the next task */
         public void run() {
             // TODO: Temporarily skip this if multi stack is enabled
@@ -360,6 +366,9 @@
 
                 // Otherwise, start the recents activity
                 startRecentsActivity(topTask, isTopTaskHome.value, true /* animate */);
+
+                // Only close the other system windows if we are actually showing recents
+                ssp.sendCloseSystemWindows(BaseStatusBar.SYSTEM_DIALOG_REASON_RECENT_APPS);
                 mLastToggleTime = SystemClock.elapsedRealtime();
             }
         } catch (ActivityNotFoundException e) {
@@ -572,9 +581,9 @@
         Rect windowRect = ssp.getWindowRect();
 
         // Update the configuration for the current state
-        config.update(mContext, ssp, ssp.getWindowRect());
+        config.update(windowRect);
 
-        if (!RecentsDebugFlags.Static.DisableSearchBar && tryAndBindSearchWidget) {
+        if (RecentsDebugFlags.Static.EnableSearchBar && tryAndBindSearchWidget) {
             // Try and pre-emptively bind the search widget on startup to ensure that we
             // have the right thumbnail bounds to animate to.
             // Note: We have to reload the widget id before we get the task stack bounds below
@@ -850,11 +859,19 @@
         if (!useThumbnailTransition) {
             // If there is no thumbnail transition, but is launching from home into recents, then
             // use a quick home transition and do the animation from home
-            if (!RecentsDebugFlags.Static.DisableSearchBar && hasRecentTasks) {
+            if (hasRecentTasks) {
                 SystemServicesProxy ssp = Recents.getSystemServices();
                 String homeActivityPackage = ssp.getHomeActivityPackageName();
-                String searchWidgetPackage = Prefs.getString(mContext,
-                        Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+                String searchWidgetPackage = null;
+                if (RecentsDebugFlags.Static.EnableSearchBar) {
+                    searchWidgetPackage = Prefs.getString(mContext,
+                            Prefs.Key.OVERVIEW_SEARCH_APP_WIDGET_PACKAGE, null);
+                } else {
+                    AppWidgetProviderInfo searchWidgetInfo = ssp.resolveSearchAppWidget();
+                    if (searchWidgetInfo != null) {
+                        searchWidgetPackage = searchWidgetInfo.provider.getPackageName();
+                    }
+                }
 
                 // Determine whether we are coming from a search owned home activity
                 boolean fromSearchHome = (homeActivityPackage != null) &&
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index 35e53f6..108029d 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -58,7 +58,7 @@
 import android.util.MutableBoolean;
 import android.util.Pair;
 import android.view.Display;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
@@ -68,6 +68,7 @@
 import com.android.systemui.R;
 import com.android.systemui.recents.RecentsDebugFlags;
 import com.android.systemui.recents.RecentsImpl;
+import com.android.systemui.statusbar.BaseStatusBar;
 
 import java.io.IOException;
 import java.util.ArrayList;
@@ -79,6 +80,7 @@
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.HOME_STACK_ID;
 import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 
 /**
  * Acts as a shim around the real system services that we need to access data from, and provides
@@ -128,7 +130,9 @@
         mDisplay = mWm.getDefaultDisplay();
         mRecentsPackage = context.getPackageName();
         mHasFreeformWorkspaceSupport =
-                mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+                mPm.hasSystemFeature(PackageManager.FEATURE_FREEFORM_WINDOW_MANAGEMENT) ||
+                        Settings.Global.getInt(context.getContentResolver(),
+                                DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
 
         // Get the dummy thumbnail width/heights
         Resources res = context.getResources();
@@ -310,7 +314,8 @@
         try {
             final ActivityOptions options = ActivityOptions.makeBasic();
             options.setDockCreateMode(createMode);
-            mIam.startActivityFromRecents(taskId, DOCKED_STACK_ID, options.toBundle());
+            options.setLaunchStackId(DOCKED_STACK_ID);
+            mIam.startActivityFromRecents(taskId, options.toBundle());
         } catch (RemoteException e) {
             e.printStackTrace();
         }
@@ -498,6 +503,18 @@
     }
 
     /**
+     * Sends a message to close other system windows.
+     */
+    public void sendCloseSystemWindows(String reason) {
+        if (ActivityManagerNative.isSystemReady()) {
+            try {
+                ActivityManagerNative.getDefault().closeSystemDialogs(reason);
+            } catch (RemoteException e) {
+            }
+        }
+    }
+
+    /**
      * Returns the activity info for a given component name.
      *
      * @param cn The component name of the activity.
@@ -634,7 +651,7 @@
         if (mPm == null) return null;
         if (RecentsDebugFlags.Static.EnableSystemServicesProxy) return null;
 
-        ArrayList<ResolveInfo> homeActivities = new ArrayList<ResolveInfo>();
+        ArrayList<ResolveInfo> homeActivities = new ArrayList<>();
         ComponentName defaultHomeActivity = mPm.getHomeActivities(homeActivities);
         if (defaultHomeActivity != null) {
             return defaultHomeActivity.getPackageName();
@@ -722,7 +739,7 @@
     /**
      * Returns the first Recents widget from the same package as the global assist activity.
      */
-    private AppWidgetProviderInfo resolveSearchAppWidget() {
+    public AppWidgetProviderInfo resolveSearchAppWidget() {
         if (mAssistComponent == null) return null;
         List<AppWidgetProviderInfo> widgets = mAwm.getInstalledProviders(
                 AppWidgetProviderInfo.WIDGET_CATEGORY_SEARCHBOX);
@@ -836,8 +853,7 @@
             ActivityOptions options) {
         if (mIam != null) {
             try {
-                mIam.startActivityFromRecents(
-                        taskId, INVALID_STACK_ID, options == null ? null : options.toBundle());
+                mIam.startActivityFromRecents(taskId, options == null ? null : options.toBundle());
                 return true;
             } catch (Exception e) {
                 Log.e(TAG, context.getString(R.string.recents_launch_error_message, taskName), e);
@@ -879,12 +895,11 @@
         }
     }
 
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) {
         if (mWm == null) return;
 
         try {
-            WindowManagerGlobal.getWindowManagerService().registerDockDividerVisibilityListener(
-                    listener);
+            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(listener);
         } catch (Exception e) {
             e.printStackTrace();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 7a92b2a..d6262ac 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -155,7 +155,7 @@
             // Add the task to the stack
             Task task = new Task(taskKey, t.affiliatedTaskId, t.affiliatedTaskColor, icon,
                     thumbnail, title, contentDescription, activityColor, !isStackTask,
-                    (i == (taskCount - 1)), config.lockToAppEnabled, t.bounds, t.taskDescription);
+                    t.bounds, t.taskDescription);
 
             allTasks.add(task);
         }
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 34a0e52..d030fc1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/Task.java
@@ -131,8 +131,6 @@
      */
     public boolean isLaunchTarget;
     public boolean isHistorical;
-    public boolean lockToThisTask;
-    public boolean lockToTaskEnabled;
 
     private ArrayList<TaskCallbacks> mCallbacks = new ArrayList<>();
 
@@ -142,8 +140,8 @@
 
     public Task(TaskKey key, int affiliationTaskId, int affiliationColor, Drawable icon,
                 Bitmap thumbnail, String title, String contentDescription, int colorPrimary,
-                boolean isHistorical, boolean lockToThisTask, boolean lockToTaskEnabled,
-                Rect bounds, ActivityManager.TaskDescription taskDescription) {
+                boolean isHistorical, Rect bounds,
+                ActivityManager.TaskDescription taskDescription) {
         boolean isInAffiliationGroup = (affiliationTaskId != key.id);
         boolean hasAffiliationGroupColor = isInAffiliationGroup && (affiliationColor != 0);
         this.key = key;
@@ -159,8 +157,6 @@
         this.bounds = bounds;
         this.taskDescription = taskDescription;
         this.isHistorical = isHistorical;
-        this.lockToThisTask = lockToTaskEnabled && lockToThisTask;
-        this.lockToTaskEnabled = lockToTaskEnabled;
     }
 
     /** Copies the other task. */
@@ -178,8 +174,6 @@
         this.bounds = o.bounds;
         this.isLaunchTarget = o.isLaunchTarget;
         this.isHistorical = o.isHistorical;
-        this.lockToThisTask = o.lockToThisTask;
-        this.lockToTaskEnabled = o.lockToTaskEnabled;
     }
 
     /**
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 6f003ab..5e720cb 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/TaskStack.java
@@ -427,8 +427,6 @@
                 removeGroup(group);
             }
         }
-        // Update the lock-to-app state
-        t.lockToThisTask = false;
     }
 
     /** Removes a task */
@@ -437,9 +435,6 @@
             boolean wasFrontMostTask = (getStackFrontMostTask() == t);
             removeTaskImpl(mStackTaskList, t);
             Task newFrontMostTask = getStackFrontMostTask();
-            if (newFrontMostTask != null && newFrontMostTask.lockToTaskEnabled) {
-                newFrontMostTask.lockToThisTask = true;
-            }
             if (mCb != null) {
                 // Notify that a task has been removed
                 mCb.onStackTaskRemoved(this, t, wasFrontMostTask, newFrontMostTask);
@@ -524,10 +519,21 @@
         mAffinitiesGroups.clear();
     }
 
-    /** Gets the front task */
+    /**
+     * Gets the front-most task in the stack.
+     */
     public Task getStackFrontMostTask() {
-        if (mStackTaskList.size() == 0) return null;
-        return mStackTaskList.getTasks().get(mStackTaskList.size() - 1);
+        ArrayList<Task> stackTasks = mStackTaskList.getTasks();
+        if (stackTasks.isEmpty()) {
+            return null;
+        }
+        for (int i = stackTasks.size() - 1; i >= 0; i--) {
+            Task task = stackTasks.get(i);
+            if (!task.isFreeformTask()) {
+                return task;
+            }
+        }
+        return null;
     }
 
     /** Gets the task keys */
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 9b1315a..c95c73b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -317,7 +317,7 @@
      * Hides the task stack and shows the empty view.
      */
     public void showEmptyView() {
-        if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+        if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
             mSearchBar.setVisibility(View.INVISIBLE);
         }
         mTaskStackView.setVisibility(View.INVISIBLE);
@@ -332,7 +332,7 @@
     public void hideEmptyView() {
         mEmptyView.setVisibility(View.INVISIBLE);
         mTaskStackView.setVisibility(View.VISIBLE);
-        if (!RecentsDebugFlags.Static.DisableSearchBar && (mSearchBar != null)) {
+        if (RecentsDebugFlags.Static.EnableSearchBar && (mSearchBar != null)) {
             mSearchBar.setVisibility(View.VISIBLE);
         }
         mTaskStackView.bringToFront();
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 10df156..9d391b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java
@@ -333,7 +333,6 @@
      * including the search bar.
      */
     public void initialize(Rect taskStackBounds, StackState state) {
-        RecentsDebugFlags debugFlags = Recents.getDebugFlags();
         RecentsConfiguration config = Recents.getConfiguration();
         int widthPadding = (int) (config.taskStackWidthPaddingPct * taskStackBounds.width());
         int heightPadding = mContext.getResources().getDimensionPixelSize(
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 830d607..94fae13 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -28,6 +28,7 @@
 import android.graphics.drawable.GradientDrawable;
 import android.os.Bundle;
 import android.os.Parcelable;
+import android.provider.Settings;
 import android.util.IntProperty;
 import android.util.Log;
 import android.util.Property;
@@ -149,7 +150,9 @@
     List<TaskView> mImmutableTaskViews = new ArrayList<>();
     List<TaskView> mTmpTaskViews = new ArrayList<>();
     LayoutInflater mInflater;
+
     boolean mTouchExplorationEnabled;
+    boolean mScreenPinningEnabled;
 
     Interpolator mFastOutSlowInInterpolator;
 
@@ -224,6 +227,8 @@
     protected void onAttachedToWindow() {
         SystemServicesProxy ssp = Recents.getSystemServices();
         mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
+        mScreenPinningEnabled = ssp.getSystemSetting(getContext(),
+                Settings.System.LOCK_TO_APP_ENABLED) != 0;
         EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY + 1);
         super.onAttachedToWindow();
     }
@@ -1023,8 +1028,7 @@
                         launchTargetTask);
                 hideTask = launchTargetTask.isFreeformTask() && task.isFreeformTask();
             }
-            tv.prepareEnterRecentsAnimation(task.isLaunchTarget, hideTask, occludesLaunchTarget,
-                    offscreenY);
+            tv.prepareEnterRecentsAnimation(hideTask, occludesLaunchTarget, offscreenY);
         }
 
         // If the enter animation started already and we haven't completed a layout yet, do the
@@ -1087,6 +1091,7 @@
                 ctx.currentTaskRect = mLayoutAlgorithm.mTaskRect;
                 ctx.currentTaskOccludesLaunchTarget = (launchTargetTask != null) &&
                         launchTargetTask.group.isTaskAboveTask(task, launchTargetTask);
+                ctx.isScreenPinningEnabled = mScreenPinningEnabled;
                 ctx.updateListener = mRequestUpdateClippingListener;
                 mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(),
                         ctx.currentTaskTransform, null);
@@ -1271,13 +1276,11 @@
             requestSynchronizeStackViewsWithModel(DEFAULT_SYNC_STACK_DURATION);
         }
 
-        // Update the new front most task
-        if (newFrontMostTask != null) {
+        // Update the new front most task's action button
+        if (mScreenPinningEnabled && newFrontMostTask != null) {
             TaskView frontTv = getChildViewForTask(newFrontMostTask);
             if (frontTv != null) {
-                frontTv.onTaskBound(newFrontMostTask);
-                frontTv.fadeInActionButton(getResources().getInteger(
-                        R.integer.recents_task_enter_from_app_duration));
+                frontTv.showActionButton(true /* fadeIn */, DEFAULT_SYNC_STACK_DURATION);
             }
         }
 
@@ -1304,7 +1307,7 @@
 
     @Override
     public void prepareViewToEnterPool(TaskView tv) {
-        Task task = tv.getTask();
+        final Task task = tv.getTask();
 
         // Report that this tasks's data is no longer being used
         Recents.getTaskLoader().unloadTaskData(task);
@@ -1314,14 +1317,13 @@
         // Update the task views list after removing the task view
         updateTaskViewsList();
 
-        // Reset the view properties
+        // Reset the view properties and view state
         tv.resetViewProperties();
-
-        // Reset the focused view state
         tv.setFocusedState(false, false /* animated */, false /* requestViewFocus */);
-
-        // Reset the clip state of the task view
         tv.setClipViewInStack(false);
+        if (mScreenPinningEnabled) {
+            tv.hideActionButton();
+        }
     }
 
     @Override
@@ -1362,6 +1364,11 @@
         if (mFocusedTask == task) {
             tv.setFocusedState(true, false /* animated */, false /* requestViewFocus */);
         }
+
+        // Restore the action button visibility if it is the front most task view
+        if (mScreenPinningEnabled && tv.getTask() == mStack.getStackFrontMostTask()) {
+            tv.showActionButton(false /* fadeIn */, 0 /* fadeInDuration */);
+        }
     }
 
     @Override
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 a3e8b2d..14909c5 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -138,6 +138,7 @@
             setBackground(new FakeShadowDrawable(res, config));
         }
         setOutlineProvider(mViewBounds);
+        setOnLongClickListener(this);
     }
 
     /** Set callback */
@@ -175,8 +176,10 @@
             public void getOutline(View view, Outline outline) {
                 // Set the outline to match the FAB background
                 outline.setOval(0, 0, mActionButtonView.getWidth(), mActionButtonView.getHeight());
+                outline.setAlpha(0.35f);
             }
         });
+        mActionButtonView.setOnClickListener(this);
         mActionButtonTranslationZ = mActionButtonView.getTranslationZ();
     }
 
@@ -293,8 +296,8 @@
 
     /** Prepares this task view for the enter-recents animations.  This is called earlier in the
      * first layout because the actual animation into recents may take a long time. */
-    void prepareEnterRecentsAnimation(boolean isTaskViewLaunchTargetTask, boolean hideTask,
-            boolean occludesLaunchTarget, int offscreenY) {
+    void prepareEnterRecentsAnimation(boolean hideTask, boolean occludesLaunchTarget,
+            int offscreenY) {
         RecentsConfiguration config = Recents.getConfiguration();
         RecentsActivityLaunchState launchState = config.getLaunchState();
         int initialDim = getDim();
@@ -303,7 +306,7 @@
         } else if (launchState.launchedHasConfigurationChanged) {
             // Just load the views as-is
         } else if (launchState.launchedFromAppWithThumbnail) {
-            if (isTaskViewLaunchTargetTask) {
+            if (mTask.isLaunchTarget) {
                 // Set the dim to 0 so we can animate it in
                 initialDim = 0;
                 // Hide the action button
@@ -342,11 +345,15 @@
         if (launchState.launchedFromAppWithThumbnail) {
             if (mTask.isLaunchTarget) {
                 ctx.postAnimationTrigger.increment();
-                // Immediately start the dim animation
+                // Start the dim animation
                 animateDimToProgress(taskViewEnterFromAppDuration,
                         ctx.postAnimationTrigger.decrementOnAnimationEnd());
-                // Animate the action button in
-                fadeInActionButton(taskViewEnterFromAppDuration);
+
+                // Start the action button animation
+                if (ctx.isScreenPinningEnabled) {
+                    showActionButton(true /* fadeIn */,
+                            taskViewEnterFromAppDuration /* fadeInDuration */);
+                }
             } else {
                 // Animate the task up if it was occluding the launch target
                 if (ctx.currentTaskOccludesLaunchTarget) {
@@ -413,17 +420,6 @@
         animate().cancel();
     }
 
-    public void fadeInActionButton(int duration) {
-        // Hide the action button
-        mActionButtonView.setAlpha(0f);
-
-        // Animate the action button in
-        mActionButtonView.animate().alpha(1f)
-                .setDuration(duration)
-                .setInterpolator(PhoneStatusBar.ALPHA_IN)
-                .start();
-    }
-
     /** Animates this task view as it leaves recents by pressing home. */
     void startExitToHomeAnimation(ViewAnimation.TaskViewExitContext ctx) {
         int taskViewExitToHomeDuration = getResources().getInteger(
@@ -468,8 +464,9 @@
                     .alpha(0f)
                     .setStartDelay(0)
                     .setDuration(taskViewExitToAppDuration)
-                    .setInterpolator(mFastOutLinearInInterpolator)
+                    .setInterpolator(PhoneStatusBar.ALPHA_OUT)
                     .withEndAction(postAnimRunnable)
+                    .withLayer()
                     .start();
         } else {
             // Hide the dismiss button
@@ -644,8 +641,6 @@
         setDim(getDimFromTaskProgress());
     }
 
-    /**** View focus state ****/
-
     /**
      * Explicitly sets the focused state of this task.
      */
@@ -672,19 +667,42 @@
         }
     }
 
+    /**
+     * Shows the action button.
+     * @param fadeIn whether or not to animate the action button in.
+     * @param fadeInDuration the duration of the action button animation, only used if
+     *                       {@param fadeIn} is true.
+     */
+    public void showActionButton(boolean fadeIn, int fadeInDuration) {
+        mActionButtonView.setVisibility(View.VISIBLE);
+
+        if (fadeIn) {
+            if (mActionButtonView.getAlpha() < 1f) {
+                mActionButtonView.setAlpha(0f);
+                mActionButtonView.animate().alpha(1f)
+                        .setDuration(fadeInDuration)
+                        .setInterpolator(PhoneStatusBar.ALPHA_IN)
+                        .withLayer()
+                        .start();
+            }
+        } else {
+            mActionButtonView.setAlpha(1f);
+        }
+    }
+
+    /**
+     * Immediately hides the action button.
+     */
+    public void hideActionButton() {
+        mActionButtonView.setVisibility(View.INVISIBLE);
+    }
+
     /**** TaskCallbacks Implementation ****/
 
     /** Binds this task view to the task */
     public void onTaskBound(Task t) {
         mTask = t;
         mTask.addCallback(this);
-
-        // Hide the action button if lock to app is disabled for this view
-        int lockButtonVisibility = (!t.lockToTaskEnabled || !t.lockToThisTask) ? GONE : VISIBLE;
-        if (mActionButtonView.getVisibility() != lockButtonVisibility) {
-            mActionButtonView.setVisibility(lockButtonVisibility);
-            requestLayout();
-        }
     }
 
     @Override
@@ -693,10 +711,6 @@
             // Bind each of the views to the new task data
             mThumbnailView.rebindToTask(mTask);
             mHeaderView.rebindToTask(mTask);
-
-            // Rebind any listeners
-            mActionButtonView.setOnClickListener(this);
-            setOnLongClickListener(this);
         }
         mTaskDataLoaded = true;
     }
@@ -708,8 +722,6 @@
             mTask.removeCallback(this);
             mThumbnailView.unbindFromTask();
             mHeaderView.unbindFromTask();
-            // Unbind any listeners
-            mActionButtonView.setOnClickListener(null);
         }
         mTaskDataLoaded = false;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
index e1d80fd..eaef51c 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/ViewAnimation.java
@@ -33,6 +33,8 @@
 
         // These following properties are updated for each task view we start the enter animation on
 
+        // Whether or not screen pinning is enabled
+        boolean isScreenPinningEnabled;
         // Whether or not the current task occludes the launch target
         boolean currentTaskOccludesLaunchTarget;
         // The task rect for the current stack
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
index 6ff7a3e..189e651 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/Divider.java
@@ -17,7 +17,8 @@
 package com.android.systemui.stackdivider;
 
 import android.content.res.Configuration;
-import android.view.IDockDividerVisibilityListener;
+import android.os.RemoteException;
+import android.view.IDockedStackListener;
 import android.view.LayoutInflater;
 import android.view.View;
 
@@ -49,7 +50,7 @@
         putComponent(Divider.class, this);
         mDockDividerVisibilityListener = new DockDividerVisibilityListener();
         SystemServicesProxy ssp = Recents.getSystemServices();
-        ssp.registerDockDividerVisibilityListener(mDockDividerVisibilityListener);
+        ssp.registerDockedStackListener(mDockDividerVisibilityListener);
     }
 
     @Override
@@ -94,10 +95,15 @@
         });
     }
 
-    class DockDividerVisibilityListener extends IDockDividerVisibilityListener.Stub {
+    class DockDividerVisibilityListener extends IDockedStackListener.Stub {
+
         @Override
-        public void onDockDividerVisibilityChanged(boolean visible) {
+        public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
             updateVisibility(visible);
         }
+
+        @Override
+        public void onDockedStackExistsChanged(boolean exists) throws RemoteException {
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
new file mode 100644
index 0000000..5ef56f3
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerHandleView.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.stackdivider;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.annotation.Nullable;
+import android.content.Context;
+import android.graphics.Canvas;
+import android.graphics.Paint;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
+import android.widget.ImageButton;
+
+import com.android.systemui.R;
+
+/**
+ * View for the handle in the docked stack divider.
+ */
+public class DividerHandleView extends ImageButton {
+
+    private final static Property<DividerHandleView, Integer> WIDTH_PROPERTY
+            = new Property<DividerHandleView, Integer>(Integer.class, "width") {
+
+        @Override
+        public Integer get(DividerHandleView object) {
+            return object.mCurrentWidth;
+        }
+
+        @Override
+        public void set(DividerHandleView object, Integer value) {
+            object.mCurrentWidth = value;
+            object.invalidate();
+        }
+    };
+
+    private final static Property<DividerHandleView, Integer> HEIGHT_PROPERTY
+            = new Property<DividerHandleView, Integer>(Integer.class, "height") {
+
+        @Override
+        public Integer get(DividerHandleView object) {
+            return object.mCurrentHeight;
+        }
+
+        @Override
+        public void set(DividerHandleView object, Integer value) {
+            object.mCurrentHeight = value;
+            object.invalidate();
+        }
+    };
+
+    private final Paint mPaint = new Paint();
+    private final int mWidth;
+    private final int mHeight;
+    private final int mCircleDiameter;
+    private final Interpolator mFastOutSlowInInterpolator;
+    private int mCurrentWidth;
+    private int mCurrentHeight;
+    private AnimatorSet mAnimator;
+
+    public DividerHandleView(Context context, @Nullable AttributeSet attrs) {
+        super(context, attrs);
+        mPaint.setColor(getResources().getColor(R.color.docked_divider_handle, null));
+        mPaint.setAntiAlias(true);
+        mWidth = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_width);
+        mHeight = getResources().getDimensionPixelSize(R.dimen.docked_divider_handle_height);
+        mCurrentWidth = mWidth;
+        mCurrentHeight = mHeight;
+        mCircleDiameter = (mWidth + mHeight) / 3;
+        mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
+                android.R.interpolator.fast_out_slow_in);
+    }
+
+    public void setTouching(boolean touching, boolean animate) {
+        if (mAnimator != null) {
+            mAnimator.cancel();
+            mAnimator = null;
+        }
+        if (!animate) {
+            if (touching) {
+                mCurrentWidth = mCircleDiameter;
+                mCurrentHeight = mCircleDiameter;
+            } else {
+                mCurrentWidth = mWidth;
+                mCurrentHeight = mHeight;
+            }
+            invalidate();
+        } else {
+            animateToTarget(touching ? mCircleDiameter : mWidth,
+                    touching ? mCircleDiameter : mHeight, touching);
+        }
+    }
+
+    private void animateToTarget(int targetWidth, int targetHeight, boolean touching) {
+        ObjectAnimator widthAnimator = ObjectAnimator.ofInt(this, WIDTH_PROPERTY,
+                mCurrentWidth, targetWidth);
+        ObjectAnimator heightAnimator = ObjectAnimator.ofInt(this, HEIGHT_PROPERTY,
+                mCurrentHeight, targetHeight);
+        mAnimator = new AnimatorSet();
+        mAnimator.playTogether(widthAnimator, heightAnimator);
+        mAnimator.setDuration(touching
+                ? DividerView.TOUCH_ANIMATION_DURATION
+                : DividerView.TOUCH_RELEASE_ANIMATION_DURATION);
+        mAnimator.setInterpolator(touching
+                ? DividerView.TOUCH_RESPONSE_INTERPOLATOR
+                : mFastOutSlowInInterpolator);
+        mAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mAnimator = null;
+            }
+        });
+        mAnimator.start();
+    }
+
+    @Override
+    protected void onDraw(Canvas canvas) {
+        int left = getWidth() / 2 - mCurrentWidth / 2;
+        int top = getHeight() / 2 - mCurrentHeight / 2;
+        int radius = Math.min(mCurrentWidth, mCurrentHeight) / 2;
+        canvas.drawRoundRect(left, top, left + mCurrentWidth, top + mCurrentHeight,
+                radius, radius, mPaint);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
index 5af172c..e43d531 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerSnapAlgorithm.java
@@ -17,25 +17,42 @@
 package com.android.systemui.stackdivider;
 
 import android.content.Context;
-import android.util.DisplayMetrics;
-import android.view.DisplayInfo;
+import android.graphics.Rect;
 
 import com.android.systemui.statusbar.FlingAnimationUtils;
 
 import java.util.ArrayList;
 
-import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
-
 /**
  * Calculates the snap targets and the snap position given a position and a velocity. All positions
  * here are to be interpreted as the left/top edge of the divider rectangle.
  */
 public class DividerSnapAlgorithm {
 
+    /**
+     * 3 snap targets: left/top has 16:9 ratio (for videos), 1:1, and right/bottom has 16:9 ratio
+     */
+    private static final int SNAP_MODE_16_9 = 0;
+
+    /**
+     * 3 snap targets: fixed ratio, 1:1, (1 - fixed ratio)
+     */
+    private static final int SNAP_FIXED_RATIO = 1;
+
+    /**
+     * 1 snap target: 1:1
+     */
+    private static final int SNAP_ONLY_1_1 = 2;
+
     private final Context mContext;
     private final FlingAnimationUtils mFlingAnimationUtils;
+    private final int mDisplayWidth;
+    private final int mDisplayHeight;
     private final int mDividerSize;
-    private final ArrayList<SnapTarget> mTargets;
+    private final ArrayList<SnapTarget> mTargets = new ArrayList<>();
+    private final Rect mInsets = new Rect();
+    private final int mSnapMode;
+    private final float mFixedRatio;
 
     /** The first target which is still splitting the screen */
     private final SnapTarget mFirstSplitTarget;
@@ -47,11 +64,19 @@
     private final SnapTarget mDismissEndTarget;
 
     public DividerSnapAlgorithm(Context ctx, FlingAnimationUtils flingAnimationUtils,
-            int dividerSize, boolean isHorizontalDivision) {
+            int displayWidth, int displayHeight, int dividerSize, boolean isHorizontalDivision,
+            Rect insets) {
         mContext = ctx;
         mFlingAnimationUtils = flingAnimationUtils;
         mDividerSize = dividerSize;
-        mTargets = calculateTargets(isHorizontalDivision);
+        mDisplayWidth = displayWidth;
+        mDisplayHeight = displayHeight;
+        mInsets.set(insets);
+        mSnapMode = ctx.getResources().getInteger(
+                com.android.internal.R.integer.config_dockedStackDividerSnapMode);
+        mFixedRatio = ctx.getResources().getFraction(
+                com.android.internal.R.fraction.docked_stack_divider_fixed_ratio, 1, 1);
+        calculateTargets(isHorizontalDivision);
         mFirstSplitTarget = mTargets.get(1);
         mLastSplitTarget = mTargets.get(mTargets.size() - 2);
         mDismissStartTarget = mTargets.get(0);
@@ -75,6 +100,40 @@
         }
     }
 
+    public float calculateDismissingFraction(int position) {
+        if (position < mFirstSplitTarget.position) {
+            return 1f - (float) position / mFirstSplitTarget.position;
+        } else if (position > mLastSplitTarget.position) {
+            return (float) (position - mLastSplitTarget.position)
+                    / (mDismissEndTarget.position - mLastSplitTarget.position);
+        }
+        return 0f;
+    }
+
+    public SnapTarget getClosestDismissTarget(int position) {
+        if (position - mDismissStartTarget.position < mDismissEndTarget.position - position) {
+            return mDismissStartTarget;
+        } else {
+            return mDismissEndTarget;
+        }
+    }
+
+    public SnapTarget getFirstSplitTarget() {
+        return mFirstSplitTarget;
+    }
+
+    public SnapTarget getLastSplitTarget() {
+        return mLastSplitTarget;
+    }
+
+    public SnapTarget getDismissStartTarget() {
+        return mDismissStartTarget;
+    }
+
+    public SnapTarget getDismissEndTarget() {
+        return mDismissEndTarget;
+    }
+
     private SnapTarget snap(int position) {
         int minIndex = -1;
         int minDistance = Integer.MAX_VALUE;
@@ -89,22 +148,61 @@
         return mTargets.get(minIndex);
     }
 
-    private ArrayList<SnapTarget> calculateTargets(boolean isHorizontalDivision) {
-        ArrayList<SnapTarget> targets = new ArrayList<>();
-        DisplayMetrics info = mContext.getResources().getDisplayMetrics();
+    private void calculateTargets(boolean isHorizontalDivision) {
+        mTargets.clear();
         int dividerMax = isHorizontalDivision
-                ? info.heightPixels
-                : info.widthPixels;
+                ? mDisplayHeight
+                : mDisplayWidth;
+        mTargets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
+        switch (mSnapMode) {
+            case SNAP_MODE_16_9:
+                addRatio16_9Targets(isHorizontalDivision);
+                break;
+            case SNAP_FIXED_RATIO:
+                addFixedDivisionTargets(isHorizontalDivision);
+                break;
+            case SNAP_ONLY_1_1:
+                addMiddleTarget(isHorizontalDivision);
+                break;
+        }
+        mTargets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
+    }
 
-        // TODO: Better calculation
-        targets.add(new SnapTarget(-mDividerSize, SnapTarget.FLAG_DISMISS_START));
-        targets.add(new SnapTarget((int) (0.3415f * dividerMax) - mDividerSize / 2,
+    private void addFixedDivisionTargets(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        mTargets.add(new SnapTarget((int) (start + mFixedRatio * (end - start)) - mDividerSize / 2,
                 SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget(dividerMax / 2 - mDividerSize / 2, SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget((int) (0.6585f * dividerMax) - mDividerSize / 2,
+        addMiddleTarget(isHorizontalDivision);
+        mTargets.add(new SnapTarget((int) (start + (1 - mFixedRatio) * (end - start))
+                - mDividerSize / 2, SnapTarget.FLAG_NONE));
+    }
+
+    private void addRatio16_9Targets(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        int startOther = isHorizontalDivision ? mInsets.left : mInsets.top;
+        int endOther = isHorizontalDivision
+                ? mDisplayWidth - mInsets.right
+                : mDisplayHeight - mInsets.bottom;
+        float size = 9.0f / 16.0f * (endOther - startOther);
+        int sizeInt = (int) Math.floor(size);
+        mTargets.add(new SnapTarget(start + sizeInt, SnapTarget.FLAG_NONE));
+        addMiddleTarget(isHorizontalDivision);
+        mTargets.add(new SnapTarget(end - sizeInt - mDividerSize, SnapTarget.FLAG_NONE));
+    }
+
+    private void addMiddleTarget(boolean isHorizontalDivision) {
+        int start = isHorizontalDivision ? mInsets.top : mInsets.left;
+        int end = isHorizontalDivision
+                ? mDisplayHeight - mInsets.bottom
+                : mDisplayWidth - mInsets.right;
+        mTargets.add(new SnapTarget(start + (end - start) / 2 - mDividerSize / 2,
                 SnapTarget.FLAG_NONE));
-        targets.add(new SnapTarget(dividerMax, SnapTarget.FLAG_DISMISS_END));
-        return targets;
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 13642eb..109cf47 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -21,12 +21,14 @@
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.graphics.Rect;
 import android.graphics.Region.Op;
 import android.hardware.display.DisplayManager;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.Display;
 import android.view.DisplayInfo;
 import android.view.MotionEvent;
@@ -34,8 +36,11 @@
 import android.view.VelocityTracker;
 import android.view.View;
 import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
 import android.view.ViewTreeObserver.InternalInsetsInfo;
 import android.view.ViewTreeObserver.OnComputeInternalInsetsListener;
+import android.view.Window;
+import android.view.WindowInsets;
 import android.view.WindowManager;
 import android.view.animation.AnimationUtils;
 import android.view.animation.Interpolator;
@@ -56,15 +61,29 @@
 public class DividerView extends FrameLayout implements OnTouchListener,
         OnComputeInternalInsetsListener {
 
+    static final long TOUCH_ANIMATION_DURATION = 150;
+    static final long TOUCH_RELEASE_ANIMATION_DURATION = 200;
+    static final Interpolator TOUCH_RESPONSE_INTERPOLATOR =
+            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
+
     private static final String TAG = "DividerView";
 
-    private ImageButton mHandle;
+    private static final int TASK_POSITION_SAME = Integer.MAX_VALUE;
+    private static final float DIM_START_FRACTION = 0.5f;
+    private static final float DIM_DAMP_FACTOR = 1.7f;
+
+    private static final PathInterpolator SLOWDOWN_INTERPOLATOR =
+            new PathInterpolator(0.5f, 1f, 0.5f, 1f);
+
+    private DividerHandleView mHandle;
     private View mBackground;
     private int mStartX;
     private int mStartY;
     private int mStartPosition;
     private int mDockSide;
     private final int[] mTempInt2 = new int[2];
+    private boolean mMoving;
+    private int mTouchSlop;
 
     private int mDividerInsets;
     private int mDisplayWidth;
@@ -73,15 +92,20 @@
     private int mDividerSize;
     private int mTouchElevation;
 
-    private final Rect mTmpRect = new Rect();
+    private final Rect mDockedRect = new Rect();
+    private final Rect mDockedTaskRect = new Rect();
+    private final Rect mOtherTaskRect = new Rect();
+    private final Rect mOtherRect = new Rect();
+    private final Rect mDockedInsetRect = new Rect();
+    private final Rect mOtherInsetRect = new Rect();
     private final Rect mLastResizeRect = new Rect();
     private final WindowManagerProxy mWindowManagerProxy = WindowManagerProxy.getInstance();
     private Interpolator mFastOutSlowInInterpolator;
-    private final Interpolator mTouchResponseInterpolator =
-            new PathInterpolator(0.3f, 0f, 0.1f, 1f);
     private DividerWindowManager mWindowManager;
     private VelocityTracker mVelocityTracker;
     private FlingAnimationUtils mFlingAnimationUtils;
+    private DividerSnapAlgorithm mSnapAlgorithm;
+    private final Rect mStableInsets = new Rect();
 
     public DividerView(Context context) {
         super(context);
@@ -103,7 +127,7 @@
     @Override
     protected void onFinishInflate() {
         super.onFinishInflate();
-        mHandle = (ImageButton) findViewById(R.id.docked_divider_handle);
+        mHandle = (DividerHandleView) findViewById(R.id.docked_divider_handle);
         mBackground = findViewById(R.id.docked_divider_background);
         mHandle.setOnTouchListener(this);
         mDividerWindowWidth = getResources().getDimensionPixelSize(
@@ -115,6 +139,7 @@
                 R.dimen.docked_stack_divider_lift_elevation);
         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(getContext(),
                 android.R.interpolator.fast_out_slow_in);
+        mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
         mFlingAnimationUtils = new FlingAnimationUtils(getContext(), 0.3f);
         updateDisplayInfo();
         boolean landscape = getResources().getConfiguration().orientation
@@ -124,6 +149,13 @@
         getViewTreeObserver().addOnComputeInternalInsetsListener(this);
     }
 
+    @Override
+    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
+        mStableInsets.set(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                insets.getStableInsetRight(), insets.getStableInsetBottom());
+        return super.onApplyWindowInsets(insets);
+    }
+
     public void setWindowManager(DividerWindowManager windowManager) {
         mWindowManager = windowManager;
     }
@@ -132,8 +164,11 @@
         return mWindowManagerProxy;
     }
 
-    public boolean startDragging() {
+    public boolean startDragging(boolean animate) {
+        mHandle.setTouching(true, animate);
         mDockSide = mWindowManagerProxy.getDockSide();
+        mSnapAlgorithm = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils, mDisplayWidth,
+                mDisplayHeight, mDividerSize, isHorizontalDivision(), mStableInsets);
         if (mDockSide != WindowManager.DOCKED_INVALID) {
             mWindowManagerProxy.setResizing(true);
             mWindowManager.setSlippery(false);
@@ -145,11 +180,16 @@
     }
 
     public void stopDragging(int position, float velocity) {
+        mHandle.setTouching(false, true /* animate */);
         fling(position, velocity);
         mWindowManager.setSlippery(true);
         releaseBackground();
     }
 
+    public DividerSnapAlgorithm getSnapAlgorithm() {
+        return mSnapAlgorithm;
+    }
+
     @Override
     public boolean onTouch(View v, MotionEvent event) {
         convertToScreenCoordinates(event);
@@ -161,19 +201,31 @@
                 mStartX = (int) event.getX();
                 mStartY = (int) event.getY();
                 getLocationOnScreen(mTempInt2);
-                boolean result = startDragging();
+                boolean result = startDragging(true /* animate */);
                 if (isHorizontalDivision()) {
                     mStartPosition = mTempInt2[1] + mDividerInsets;
                 } else {
                     mStartPosition = mTempInt2[0] + mDividerInsets;
                 }
+                mMoving = false;
                 return result;
             case MotionEvent.ACTION_MOVE:
                 mVelocityTracker.addMovement(event);
                 int x = (int) event.getX();
                 int y = (int) event.getY();
-                if (mDockSide != WindowManager.DOCKED_INVALID) {
-                    resizeStack(calculatePosition(x, y));
+                boolean exceededTouchSlop =
+                        isHorizontalDivision() && Math.abs(y - mStartY) > mTouchSlop
+                                || (!isHorizontalDivision() && Math.abs(x - mStartX) > mTouchSlop);
+                if (!mMoving && exceededTouchSlop) {
+                    mStartX = x;
+                    mStartY = y;
+                    mMoving = true;
+                }
+                if (mMoving && mDockSide != WindowManager.DOCKED_INVALID) {
+                    int position = calculatePosition(x, y);
+                    SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position,
+                            0 /* velocity */);
+                    resizeStack(calculatePosition(x, y), snapTarget.position, snapTarget);
                 }
                 break;
             case MotionEvent.ACTION_UP:
@@ -187,6 +239,7 @@
                 int position = calculatePosition(x, y);
                 stopDragging(position, isHorizontalDivision() ? mVelocityTracker.getYVelocity()
                         : mVelocityTracker.getXVelocity());
+                mMoving = false;
                 break;
         }
         return true;
@@ -197,14 +250,16 @@
     }
 
     private void fling(int position, float velocity) {
-        final SnapTarget snapTarget = new DividerSnapAlgorithm(getContext(), mFlingAnimationUtils,
-                mDividerSize, isHorizontalDivision()).calculateSnapTarget(position, velocity);
+        final SnapTarget snapTarget = mSnapAlgorithm.calculateSnapTarget(position, velocity);
 
         ValueAnimator anim = ValueAnimator.ofInt(position, snapTarget.position);
         anim.addUpdateListener(new AnimatorUpdateListener() {
             @Override
             public void onAnimationUpdate(ValueAnimator animation) {
-                resizeStack((Integer) animation.getAnimatedValue());
+                resizeStack((Integer) animation.getAnimatedValue(),
+                        animation.getAnimatedFraction() == 1f
+                                ? TASK_POSITION_SAME
+                                : snapTarget.position, snapTarget);
             }
         });
         anim.addListener(new AnimatorListenerAdapter() {
@@ -236,6 +291,7 @@
         } else {
             mWindowManagerProxy.maximizeDockedStack();
         }
+        mWindowManagerProxy.setResizeDimLayer(false, -1, 0f);
     }
 
     private void liftBackground() {
@@ -245,29 +301,33 @@
             mBackground.animate().scaleX(1.4f);
         }
         mBackground.animate()
-                .setInterpolator(mTouchResponseInterpolator)
-                .setDuration(150)
-                .translationZ(mTouchElevation);
+                .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+                .setDuration(TOUCH_ANIMATION_DURATION)
+                .translationZ(mTouchElevation)
+                .start();
 
         // Lift handle as well so it doesn't get behind the background, even though it doesn't
         // cast shadow.
         mHandle.animate()
-                .setInterpolator(mTouchResponseInterpolator)
-                .setDuration(150)
-                .translationZ(mTouchElevation);
+                .setInterpolator(TOUCH_RESPONSE_INTERPOLATOR)
+                .setDuration(TOUCH_ANIMATION_DURATION)
+                .translationZ(mTouchElevation)
+                .start();
     }
 
     private void releaseBackground() {
         mBackground.animate()
                 .setInterpolator(mFastOutSlowInInterpolator)
-                .setDuration(200)
+                .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
                 .translationZ(0)
                 .scaleX(1f)
-                .scaleY(1f);
+                .scaleY(1f)
+                .start();
         mHandle.animate()
                 .setInterpolator(mFastOutSlowInInterpolator)
-                .setDuration(200)
-                .translationZ(0);
+                .setDuration(TOUCH_RELEASE_ANIMATION_DURATION)
+                .translationZ(0)
+                .start();
     }
 
     @Override
@@ -332,17 +392,184 @@
         }
     }
 
-    public void resizeStack(int position) {
-        calculateBoundsForPosition(position, mDockSide, mTmpRect);
-        if (mTmpRect.equals(mLastResizeRect)) {
+    private int invertDockSide(int dockSide) {
+        switch (dockSide) {
+            case WindowManager.DOCKED_LEFT:
+                return WindowManager.DOCKED_RIGHT;
+            case WindowManager.DOCKED_TOP:
+                return WindowManager.DOCKED_BOTTOM;
+            case WindowManager.DOCKED_RIGHT:
+                return WindowManager.DOCKED_LEFT;
+            case WindowManager.DOCKED_BOTTOM:
+                return WindowManager.DOCKED_TOP;
+            default:
+                return WindowManager.DOCKED_INVALID;
+        }
+    }
+
+    private void alignTopLeft(Rect containingRect, Rect rect) {
+        int width = rect.width();
+        int height = rect.height();
+        rect.set(containingRect.left, containingRect.top,
+                containingRect.left + width, containingRect.top + height);
+    }
+
+    private void alignBottomRight(Rect containingRect, Rect rect) {
+        int width = rect.width();
+        int height = rect.height();
+        rect.set(containingRect.right - width, containingRect.bottom - height,
+                containingRect.right, containingRect.bottom);
+    }
+
+    public void resizeStack(int position, int taskPosition, SnapTarget taskSnapTarget) {
+        calculateBoundsForPosition(position, mDockSide, mDockedRect);
+
+        if (mDockedRect.equals(mLastResizeRect)) {
             return;
         }
 
         // Make sure shadows are updated
         mBackground.invalidate();
 
-        mLastResizeRect.set(mTmpRect);
-        mWindowManagerProxy.resizeDockedStack(mTmpRect);
+        mLastResizeRect.set(mDockedRect);
+        if (taskPosition != TASK_POSITION_SAME) {
+            calculateBoundsForPosition(position, invertDockSide(mDockSide), mOtherRect);
+            int dockSideInverted = invertDockSide(mDockSide);
+            int taskPositionDocked =
+                    restrictDismissingTaskPosition(taskPosition, mDockSide, taskSnapTarget);
+            int taskPositionOther =
+                    restrictDismissingTaskPosition(taskPosition, dockSideInverted, taskSnapTarget);
+            calculateBoundsForPosition(taskPositionDocked, mDockSide, mDockedTaskRect);
+            calculateBoundsForPosition(taskPositionOther, dockSideInverted, mOtherTaskRect);
+            alignTopLeft(mDockedRect, mDockedTaskRect);
+            alignTopLeft(mOtherRect, mOtherTaskRect);
+            mDockedInsetRect.set(mDockedTaskRect);
+            mOtherInsetRect.set(mOtherTaskRect);
+            if (dockSideTopLeft(mDockSide)) {
+                alignTopLeft(mDockedRect, mDockedInsetRect);
+                alignBottomRight(mOtherRect, mOtherInsetRect);
+            } else {
+                alignBottomRight(mDockedRect, mDockedInsetRect);
+                alignTopLeft(mOtherRect, mOtherInsetRect);
+            }
+            applyDismissingParallax(mDockedTaskRect, mDockSide, taskSnapTarget, position,
+                    taskPositionDocked);
+            applyDismissingParallax(mOtherTaskRect, dockSideInverted, taskSnapTarget, position,
+                    taskPositionOther);
+            mWindowManagerProxy.resizeDockedStack(mDockedRect, mDockedTaskRect, mDockedInsetRect,
+                    mOtherTaskRect, mOtherInsetRect);
+        } else {
+            mWindowManagerProxy.resizeDockedStack(mDockedRect, null, null, null, null);
+        }
+        float fraction = mSnapAlgorithm.calculateDismissingFraction(position);
+        fraction = Math.max(0,
+                Math.min((fraction / DIM_START_FRACTION - 1f) / DIM_DAMP_FACTOR, 1f));
+        mWindowManagerProxy.setResizeDimLayer(fraction != 0f,
+                getStackIdForDismissTarget(mSnapAlgorithm.getClosestDismissTarget(position)),
+                fraction);
+    }
+
+    /**
+     * When the snap target is dismissing one side, make sure that the dismissing side doesn't get
+     * 0 size.
+     */
+    private int restrictDismissingTaskPosition(int taskPosition, int dockSide,
+            SnapTarget snapTarget) {
+        if (snapTarget.flag == SnapTarget.FLAG_DISMISS_START && dockSideTopLeft(dockSide)) {
+            return mSnapAlgorithm.getFirstSplitTarget().position;
+        } else if (snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+                && dockSideBottomRight(dockSide)) {
+            return mSnapAlgorithm.getLastSplitTarget().position;
+        } else {
+            return taskPosition;
+        }
+    }
+
+    /**
+     * Applies a parallax to the task when dismissing.
+     */
+    private void applyDismissingParallax(Rect taskRect, int dockSide, SnapTarget snapTarget,
+            int position, int taskPosition) {
+        float fraction = Math.min(1, Math.max(0,
+                mSnapAlgorithm.calculateDismissingFraction(position)));
+        SnapTarget dismissTarget = null;
+        SnapTarget splitTarget = null;
+        if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_START
+                || snapTarget == mSnapAlgorithm.getFirstSplitTarget())
+                && dockSideTopLeft(dockSide)) {
+            dismissTarget = mSnapAlgorithm.getDismissStartTarget();
+            splitTarget = mSnapAlgorithm.getFirstSplitTarget();
+        } else if ((snapTarget.flag == SnapTarget.FLAG_DISMISS_END
+                || snapTarget == mSnapAlgorithm.getLastSplitTarget())
+                && dockSideBottomRight(dockSide)) {
+            dismissTarget = mSnapAlgorithm.getDismissEndTarget();
+            splitTarget = mSnapAlgorithm.getLastSplitTarget();
+        }
+        if (dismissTarget != null && fraction > 0f
+                && isDismissing(splitTarget, position, dockSide)) {
+            fraction = calculateParallaxDismissingFraction(fraction);
+            int offsetPosition = (int) (taskPosition +
+                    fraction * (dismissTarget.position - splitTarget.position));
+            int width = taskRect.width();
+            int height = taskRect.height();
+            switch (dockSide) {
+                case WindowManager.DOCKED_LEFT:
+                    taskRect.left = offsetPosition - width;
+                    taskRect.right = offsetPosition;
+                    break;
+                case WindowManager.DOCKED_RIGHT:
+                    taskRect.left = offsetPosition + mDividerSize;
+                    taskRect.right = offsetPosition + width + mDividerSize;
+                    break;
+                case WindowManager.DOCKED_TOP:
+                    taskRect.top = offsetPosition - height;
+                    taskRect.bottom = offsetPosition;
+                    break;
+                case WindowManager.DOCKED_BOTTOM:
+                    taskRect.top = offsetPosition + mDividerSize;
+                    taskRect.bottom = offsetPosition + height + mDividerSize;
+                    break;
+            }
+        }
+    }
+
+    /**
+     * @return for a specified {@code fraction}, this returns an adjusted value that simulates a
+     *         slowing down parallax effect
+     */
+    private static float calculateParallaxDismissingFraction(float fraction) {
+        return SLOWDOWN_INTERPOLATOR.getInterpolation(fraction) / 3.5f;
+    }
+
+    private static boolean isDismissing(SnapTarget snapTarget, int position, int dockSide) {
+        if (dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT) {
+            return position < snapTarget.position;
+        } else {
+            return position > snapTarget.position;
+        }
+    }
+
+    private int getStackIdForDismissTarget(SnapTarget dismissTarget) {
+        if (dismissTarget.flag == SnapTarget.FLAG_DISMISS_START &&
+                (mDockSide == WindowManager.DOCKED_LEFT || mDockSide == WindowManager.DOCKED_TOP)) {
+            return StackId.DOCKED_STACK_ID;
+        } else {
+            return StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+        }
+    }
+
+    /**
+     * @return true if and only if {@code dockSide} is top or left
+     */
+    private static boolean dockSideTopLeft(int dockSide) {
+        return dockSide == WindowManager.DOCKED_TOP || dockSide == WindowManager.DOCKED_LEFT;
+    }
+
+    /**
+     * @return true if and only if {@code dockSide} is bottom or right
+     */
+    private static boolean dockSideBottomRight(int dockSide) {
+        return dockSide == WindowManager.DOCKED_BOTTOM || dockSide == WindowManager.DOCKED_RIGHT;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
index 2251874..161f873 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerWindowManager.java
@@ -50,6 +50,9 @@
                         | FLAG_WATCH_OUTSIDE_TOUCH | FLAG_SPLIT_TOUCH | FLAG_SLIPPERY,
                 PixelFormat.TRANSLUCENT);
         mLp.setTitle(WINDOW_TITLE);
+        view.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
+                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
+                | View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
         mWindowManager.addView(view, mLp);
         mView = view;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
index ef47d8d..2791dfc 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/WindowManagerProxy.java
@@ -40,18 +40,41 @@
     private static final WindowManagerProxy sInstance = new WindowManagerProxy();
 
     @GuardedBy("mResizeRect")
-    private final Rect mResizeRect = new Rect();
-    private final Rect mTmpRect = new Rect();
+    private final Rect mDockedRect = new Rect();
+    private final Rect mTempDockedTaskRect = new Rect();
+    private final Rect mTempDockedInsetRect = new Rect();
+    private final Rect mTempOtherTaskRect = new Rect();
+    private final Rect mTempOtherInsetRect = new Rect();
+
+    private final Rect mTmpRect1 = new Rect();
+    private final Rect mTmpRect2 = new Rect();
+    private final Rect mTmpRect3 = new Rect();
+    private final Rect mTmpRect4 = new Rect();
+    private final Rect mTmpRect5 = new Rect();
+
+    private boolean mDimLayerVisible;
+    private int mDimLayerTargetStack;
+    private float mDimLayerAlpha;
+
     private final ExecutorService mExecutor = Executors.newSingleThreadExecutor();
 
     private final Runnable mResizeRunnable = new Runnable() {
         @Override
         public void run() {
-            synchronized (mResizeRect) {
-                mTmpRect.set(mResizeRect);
+            synchronized (mDockedRect) {
+                mTmpRect1.set(mDockedRect);
+                mTmpRect2.set(mTempDockedTaskRect);
+                mTmpRect3.set(mTempDockedInsetRect);
+                mTmpRect4.set(mTempOtherTaskRect);
+                mTmpRect5.set(mTempOtherInsetRect);
             }
             try {
-                ActivityManagerNative.getDefault().resizeStack(DOCKED_STACK_ID, mTmpRect, true);
+                ActivityManagerNative.getDefault()
+                        .resizeDockedStack(mTmpRect1,
+                                mTmpRect2.isEmpty() ? null : mTmpRect2,
+                                mTmpRect3.isEmpty() ? null : mTmpRect3,
+                                mTmpRect4.isEmpty() ? null : mTmpRect4,
+                                mTmpRect5.isEmpty() ? null : mTmpRect5);
             } catch (RemoteException e) {
                 Log.w(TAG, "Failed to resize stack: " + e);
             }
@@ -80,6 +103,18 @@
         }
     };
 
+    private final Runnable mDimLayerRunnable = new Runnable() {
+        @Override
+        public void run() {
+            try {
+                WindowManagerGlobal.getWindowManagerService().setResizeDimLayer(mDimLayerVisible,
+                        mDimLayerTargetStack, mDimLayerAlpha);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failed to resize stack: " + e);
+            }
+        }
+    };
+
     private WindowManagerProxy() {
     }
 
@@ -87,9 +122,30 @@
         return sInstance;
     }
 
-    public void resizeDockedStack(Rect rect) {
-        synchronized (mResizeRect) {
-            mResizeRect.set(rect);
+    public void resizeDockedStack(Rect docked, Rect tempDockedTaskRect, Rect tempDockedInsetRect,
+            Rect tempOtherTaskRect, Rect tempOtherInsetRect) {
+        synchronized (mDockedRect) {
+            mDockedRect.set(docked);
+            if (tempDockedTaskRect != null) {
+                mTempDockedTaskRect.set(tempDockedTaskRect);
+            } else {
+                mTempDockedTaskRect.setEmpty();
+            }
+            if (tempDockedInsetRect != null) {
+                mTempDockedInsetRect.set(tempDockedInsetRect);
+            } else {
+                mTempDockedInsetRect.setEmpty();
+            }
+            if (tempOtherTaskRect != null) {
+                mTempOtherTaskRect.set(tempOtherTaskRect);
+            } else {
+                mTempOtherTaskRect.setEmpty();
+            }
+            if (tempOtherInsetRect != null) {
+                mTempOtherInsetRect.set(tempOtherInsetRect);
+            } else {
+                mTempOtherInsetRect.setEmpty();
+            }
         }
         mExecutor.execute(mResizeRunnable);
     }
@@ -123,4 +179,11 @@
         }
         return DOCKED_INVALID;
     }
+
+    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+        mDimLayerVisible = visible;
+        mDimLayerTargetStack = targetStackId;
+        mDimLayerAlpha = alpha;
+        mExecutor.execute(mDimLayerRunnable);
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 1d7651c..5906bda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -148,8 +148,9 @@
     protected static final int INTERRUPTION_THRESHOLD = 10;
     protected static final String SETTING_HEADS_UP_TICKER = "ticker_gets_heads_up";
 
-    // Should match the value in PhoneWindowManager
+    // Should match the values in PhoneWindowManager
     public static final String SYSTEM_DIALOG_REASON_RECENT_APPS = "recentapps";
+    public static final String SYSTEM_DIALOG_REASON_HOME_KEY = "homekey";
 
     private static final String BANNER_ACTION_CANCEL =
             "com.android.systemui.statusbar.banner_action_cancel";
@@ -970,7 +971,7 @@
         ((ImageView) row.findViewById(android.R.id.icon)).setImageDrawable(pkgicon);
         ((TextView) row.findViewById(R.id.pkgname)).setText(appname);
 
-        final View settingsButton = guts.findViewById(R.id.notification_inspect_item);
+        final View settingsButton = guts.findViewById(R.id.more_settings);
         if (appUid >= 0) {
             final int appUidF = appUid;
             settingsButton.setOnClickListener(new View.OnClickListener() {
@@ -983,6 +984,13 @@
             settingsButton.setVisibility(View.GONE);
         }
 
+        row.findViewById(R.id.done).setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                dismissPopups();
+            }
+        });
+
         guts.bindImportance(sbn, row, mNotificationData.getImportance(sbn.getKey()));
     }
 
@@ -1182,7 +1190,6 @@
 
     protected void toggleRecents() {
         if (mRecents != null) {
-            sendCloseSystemWindows(mContext, SYSTEM_DIALOG_REASON_RECENT_APPS);
             mRecents.toggleRecents(mDisplay, mLayoutDirection, getStatusBarView());
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index f7680a7..3cc1ab9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -292,6 +292,15 @@
         return false;
     }
 
+    public boolean shouldSuppressScreenOn(String key) {
+        if (mRankingMap != null) {
+            mRankingMap.getRanking(key, mTmpRanking);
+            return (mTmpRanking.getSuppressedVisualEffects()
+                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0;
+        }
+        return false;
+    }
+
     public int getImportance(String key) {
         if (mRankingMap != null) {
             mRankingMap.getRanking(key, mTmpRanking);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
index 58c9722..d0c14f1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarApps.java
@@ -746,7 +746,7 @@
         // Launch or bring the activity to front.
         final IActivityManager iAm = ActivityManagerNative.getDefault();
         try {
-            iAm.startActivityFromRecents(taskPersistentId, INVALID_STACK_ID, null /* options */);
+            iAm.startActivityFromRecents(taskPersistentId, null /* options */);
         } catch (RemoteException e) {
             Slog.e(TAG, "Exception when activating a recent task", e);
         } catch (IllegalArgumentException e) {
@@ -1104,6 +1104,10 @@
                 }
             });
         }
+
+        @Override
+        public void onActivityPinned() {
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
index 79bd626..cc85d0f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarGestureHelper.java
@@ -29,6 +29,8 @@
 import com.android.systemui.R;
 import com.android.systemui.RecentsComponent;
 import com.android.systemui.stackdivider.Divider;
+import com.android.systemui.stackdivider.DividerSnapAlgorithm.SnapTarget;
+import com.android.systemui.stackdivider.DividerView;
 import com.android.systemui.tuner.TunerService;
 
 import static android.view.WindowManager.*;
@@ -189,7 +191,7 @@
                 mRecentsComponent.dockTopTask(mDragMode == DRAG_MODE_RECENTS, createMode,
                         initialBounds);
                 if (mDragMode == DRAG_MODE_DIVIDER) {
-                    mDivider.getView().startDragging();
+                    mDivider.getView().startDragging(false /* animate */);
                 }
                 mDockWindowTouchSlopExceeded = true;
                 MetricsLogger.action(mContext,
@@ -198,8 +200,10 @@
             }
         } else {
             if (mDragMode == DRAG_MODE_DIVIDER) {
-                mDivider.getView().resizeStack(
-                        !mIsVertical ? (int) event.getRawY() : (int) event.getRawX());
+                int position = !mIsVertical ? (int) event.getRawY() : (int) event.getRawX();
+                SnapTarget snapTarget = mDivider.getView().getSnapAlgorithm()
+                        .calculateSnapTarget(position, 0f /* velocity */);
+                mDivider.getView().resizeStack(position, snapTarget.position, snapTarget);
             } else if (mDragMode == DRAG_MODE_RECENTS) {
                 mRecentsComponent.onDraggingInRecents(event.getRawY());
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index cddb1fc..a3d0ce6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,11 +36,13 @@
 import android.util.Log;
 import android.view.Display;
 import android.view.Gravity;
+import android.view.IDockedStackListener.Stub;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
+import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 import android.widget.ImageView;
@@ -227,8 +229,8 @@
         return mCurrentView;
     }
 
-    public View getRecentsButton() {
-        return mCurrentView.findViewById(R.id.recent_apps);
+    public KeyButtonView getRecentsButton() {
+        return (KeyButtonView) mCurrentView.findViewById(R.id.recent_apps);
     }
 
     public View getMenuButton() {
@@ -455,6 +457,32 @@
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
 
         updateRTLOrder();
+
+        try {
+            WindowManagerGlobal.getWindowManagerService().registerDockedStackListener(new Stub() {
+                @Override
+                public void onDividerVisibilityChanged(boolean visible) throws RemoteException {
+                }
+
+                @Override
+                public void onDockedStackExistsChanged(final boolean exists) throws RemoteException {
+                    mHandler.post(new Runnable() {
+                        @Override
+                        public void run() {
+                            updateRecentsIcon(exists);
+                        }
+                    });
+                }
+            });
+        } catch (RemoteException e) {
+            Log.e(TAG, "Failed registering docked stack exists listener", e);
+        }
+    }
+
+    private void updateRecentsIcon(boolean dockedStackExists) {
+        getRecentsButton().setImageResource(dockedStackExists
+                ? R.drawable.ic_sysbar_docked
+                : R.drawable.ic_sysbar_recent);
     }
 
     public boolean isVertical() {
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 80fcba60e..78d09e3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -1269,19 +1269,26 @@
         }
 
         if (!isHeadsUped && notification.getNotification().fullScreenIntent != null) {
-            // Stop screensaver if the notification has a full-screen intent.
-            // (like an incoming phone call)
-            awakenDreams();
+            if (mNotificationData.shouldSuppressScreenOn(notification.getKey())) {
+                if (DEBUG) {
+                    Log.d(TAG, "No Fullscreen intent: suppressed by DND: " + notification.getKey());
+                }
+            } else {
+                // Stop screensaver if the notification has a full-screen intent.
+                // (like an incoming phone call)
+                awakenDreams();
 
-            // not immersive & a full-screen alert should be shown
-            if (DEBUG) Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
-            try {
-                EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
-                        notification.getKey());
-                notification.getNotification().fullScreenIntent.send();
-                shadeEntry.notifyFullScreenIntentLaunched();
-                MetricsLogger.count(mContext, "note_fullscreen", 1);
-            } catch (PendingIntent.CanceledException e) {
+                // not immersive & a full-screen alert should be shown
+                if (DEBUG)
+                    Log.d(TAG, "Notification has fullScreenIntent; sending fullScreenIntent");
+                try {
+                    EventLog.writeEvent(EventLogTags.SYSUI_FULLSCREEN_NOTIFICATION,
+                            notification.getKey());
+                    notification.getNotification().fullScreenIntent.send();
+                    shadeEntry.notifyFullScreenIntentLaunched();
+                    MetricsLogger.count(mContext, "note_fullscreen", 1);
+                } catch (PendingIntent.CanceledException e) {
+                }
             }
         }
         addNotificationViews(shadeEntry, ranking);
@@ -4120,32 +4127,6 @@
         return false;
     }
 
-    // Recents
-
-    @Override
-    protected void showRecents(boolean triggeredFromAltTab) {
-        // Set the recents visibility flag
-        mSystemUiVisibility |= View.RECENT_APPS_VISIBLE;
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-        super.showRecents(triggeredFromAltTab);
-    }
-
-    @Override
-    protected void hideRecents(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) {
-        // Unset the recents visibility flag
-        mSystemUiVisibility &= ~View.RECENT_APPS_VISIBLE;
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-        super.hideRecents(triggeredFromAltTab, triggeredFromHomeKey);
-    }
-
-    @Override
-    protected void toggleRecents() {
-        // Toggle the recents visibility flag
-        mSystemUiVisibility ^= View.RECENT_APPS_VISIBLE;
-        notifyUiVisibilityChanged(mSystemUiVisibility);
-        super.toggleRecents();
-    }
-
     public void updateRecentsVisibility(boolean visible) {
         // Update the recents visibility flag
         if (visible) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
index e6d837a..5c856e8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QSTileHost.java
@@ -18,30 +18,25 @@
 
 import android.app.ActivityManager;
 import android.app.PendingIntent;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.res.Resources;
-import android.os.Binder;
 import android.os.HandlerThread;
 import android.os.Looper;
 import android.os.Process;
-import android.os.RemoteException;
 import android.provider.Settings;
-import android.service.quicksettings.IQSService;
-import android.service.quicksettings.Tile;
 import android.text.TextUtils;
 import android.util.Log;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSTile;
+import com.android.systemui.qs.external.CustomTile;
+import com.android.systemui.qs.external.TileServices;
 import com.android.systemui.qs.tiles.AirplaneModeTile;
 import com.android.systemui.qs.tiles.BatteryTile;
 import com.android.systemui.qs.tiles.BluetoothTile;
 import com.android.systemui.qs.tiles.CastTile;
 import com.android.systemui.qs.tiles.CellularTile;
 import com.android.systemui.qs.tiles.ColorInversionTile;
-import com.android.systemui.qs.tiles.CustomTile;
 import com.android.systemui.qs.tiles.DndTile;
 import com.android.systemui.qs.tiles.FlashlightTile;
 import com.android.systemui.qs.tiles.HotspotTile;
@@ -76,7 +71,7 @@
 import java.util.Map;
 
 /** Platform implementation of the quick settings tile host **/
-public final class QSTileHost extends IQSService.Stub implements QSTile.Host, Tunable {
+public final class QSTileHost implements QSTile.Host, Tunable {
     private static final String TAG = "QSTileHost";
     private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
 
@@ -100,6 +95,7 @@
     private final KeyguardMonitor mKeyguard;
     private final SecurityController mSecurity;
     private final BatteryController mBattery;
+    private final TileServices mServices;
 
     private final List<Callback> mCallbacks = new ArrayList<>();
 
@@ -131,6 +127,8 @@
         ht.start();
         mLooper = ht.getLooper();
 
+        mServices = new TileServices(this, mLooper);
+
         TunerService.get(mContext).addTunable(this, TILES_SETTING);
     }
 
@@ -256,6 +254,10 @@
         return mSecurity;
     }
 
+    public TileServices getTileServices() {
+        return mServices;
+    }
+
     @Override
     public void onTuningChanged(String key, String newValue) {
         if (!TILES_SETTING.equals(key)) {
@@ -306,50 +308,6 @@
                 TextUtils.join(",", specs), ActivityManager.getCurrentUser());
     }
 
-    @Override
-    public void updateQsTile(Tile tile) throws RemoteException {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
-        if (customTile != null) {
-            customTile.updateState(tile);
-            customTile.refreshState();
-        }
-    }
-
-    @Override
-    public void onShowDialog(Tile tile) throws RemoteException {
-        verifyCaller(tile.getComponentName().getPackageName());
-        CustomTile customTile = getTileForComponent(tile.getComponentName());
-        if (customTile != null) {
-            customTile.onDialogShown();
-            collapsePanels();
-        }
-    }
-
-    private void verifyCaller(String packageName) {
-        try {
-            int uid = mContext.getPackageManager().getPackageUid(packageName,
-                    Binder.getCallingUserHandle().getIdentifier());
-            if (Binder.getCallingUid() != uid) {
-                throw new SecurityException("Component outside caller's uid");
-            }
-        } catch (NameNotFoundException e) {
-            throw new SecurityException(e);
-        }
-    }
-
-    private CustomTile getTileForComponent(ComponentName component) {
-        // TODO: Build map for easier lookup.
-        for (QSTile<?> qsTile : mTiles.values()) {
-            if (qsTile instanceof CustomTile) {
-                if (((CustomTile) qsTile).getComponent().equals(component)) {
-                    return (CustomTile) qsTile;
-                }
-            }
-        }
-        return null;
-    }
-
     public QSTile<?> createTile(String tileSpec) {
         if (tileSpec.equals("wifi")) return WifiTile.isSupported(this)
                 ? new WifiTile(this) : null;
@@ -374,7 +332,10 @@
         // Intent tiles.
         else if (tileSpec.startsWith(IntentTile.PREFIX)) return IntentTile.create(this,tileSpec);
         else if (tileSpec.startsWith(CustomTile.PREFIX)) return CustomTile.create(this,tileSpec);
-        else throw new IllegalArgumentException("Bad tile spec: " + tileSpec);
+        else {
+            Log.w(TAG, "Bad tile spec: " + tileSpec);
+            return null;
+        }
     }
 
     public static List<String> loadTileSpecs(Context context, String tileList) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
index 1372cca..a91f6a2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStatusBarHeader.java
@@ -24,7 +24,6 @@
 import android.graphics.drawable.Animatable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.util.Log;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
@@ -135,7 +134,6 @@
     @Override
     public void onNextAlarmChanged(AlarmManager.AlarmClockInfo nextAlarm) {
         mNextAlarm = nextAlarm;
-        Log.d(TAG, "Got alarm update " + (nextAlarm != null));
         if (nextAlarm != null) {
             mAlarmStatus.setText(KeyguardStatusView.formatNextAlarm(getContext(), nextAlarm));
         }
@@ -179,10 +177,8 @@
 
     private void updateListeners() {
         if (mListening) {
-            Log.d(TAG, "Listening for Alarms");
             mNextAlarmController.addStateChangedCallback(this);
         } else {
-            Log.d(TAG, "Not listening for Alarms");
             mNextAlarmController.removeStateChangedCallback(this);
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index 1e3b0f1..9081af1 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -153,8 +153,11 @@
     private static TunerService sInstance;
 
     public static TunerService get(Context context) {
-        SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
-        TunerService service = sysUi.getComponent(TunerService.class);
+        TunerService service = null;
+        if (context.getApplicationContext() instanceof SystemUIApplication) {
+            SystemUIApplication sysUi = (SystemUIApplication) context.getApplicationContext();
+            service = sysUi.getComponent(TunerService.class);
+        }
         if (service == null) {
             // Can't get it as a component, must in the tuner, lets just create one for now.
             return getStaticService(context);
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
index 9d4ec10..3c63aae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialog.java
@@ -648,7 +648,7 @@
         if (D.BUG) Log.d(TAG, "updateFooterH");
         final boolean wasVisible = mZenFooter.getVisibility() == View.VISIBLE;
         final boolean visible = mState.zenMode != Global.ZEN_MODE_OFF
-                && mAudioManager.isStreamAffectedByRingerMode(mActiveStream);
+                && (mAudioManager.isStreamAffectedByRingerMode(mActiveStream) || mExpanded);
         if (wasVisible != visible && !visible) {
             prepareForCollapse();
         }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
index cd47ac1..38d8de0 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/ZenModePanel.java
@@ -510,7 +510,7 @@
         GregorianCalendar weekRange = new GregorianCalendar();
         final long now = weekRange.getTimeInMillis();
         setToMidnight(weekRange);
-        weekRange.roll(Calendar.DATE, 6);
+        weekRange.add(Calendar.DATE, 6);
         final long nextAlarmMs = mController.getNextAlarm();
         if (nextAlarmMs > 0) {
             GregorianCalendar nextAlarm = new GregorianCalendar();
diff --git a/packages/SystemUI/tests/AndroidManifest.xml b/packages/SystemUI/tests/AndroidManifest.xml
index c21af24..2825601 100644
--- a/packages/SystemUI/tests/AndroidManifest.xml
+++ b/packages/SystemUI/tests/AndroidManifest.xml
@@ -19,10 +19,16 @@
 
     <uses-permission android:name="android.permission.INJECT_EVENTS" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
+    <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+    <uses-permission android:name="android.permission.MANAGE_USERS" />
 
     <application>
         <uses-library android:name="android.test.runner" />
         <activity android:name="com.android.systemui.screenshot.ScreenshotStubActivity" />
+
+        <service
+            android:name="com.android.systemui.qs.external.TileLifecycleManagerTests$FakeTileService"
+            android:process=":killable" />
     </application>
 
     <instrumentation android:name="android.test.InstrumentationTestRunner"
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
new file mode 100644
index 0000000..6ebf488
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileLifecycleManagerTests.java
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.qs.external;
+
+import android.app.Service;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
+import android.content.pm.PackageManager;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.os.IBinder;
+import android.os.Process;
+import android.os.RemoteException;
+import android.os.UserHandle;
+import android.service.quicksettings.IQSService;
+import android.service.quicksettings.IQSTileService;
+import android.service.quicksettings.Tile;
+import android.test.AndroidTestCase;
+import android.util.ArraySet;
+import android.util.Log;
+
+public class TileLifecycleManagerTests extends AndroidTestCase {
+    public static final String TILE_UPDATE_BROADCAST = "com.android.systemui.tests.TILE_UPDATE";
+    public static final String EXTRA_CALLBACK = "callback";
+
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileLifecycleManager mStateManager;
+    private final Object mBroadcastLock = new Object();
+    private final ArraySet<String> mCallbacks = new ArraySet<>();
+    private boolean mBound;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mStateManager = new TileLifecycleManager(mHandler, getContext(),
+                new Intent(mContext, FakeTileService.class), new UserHandle(UserHandle.myUserId()));
+        mCallbacks.clear();
+        getContext().registerReceiver(mReceiver, new IntentFilter(TILE_UPDATE_BROADCAST));
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        if (mBound) {
+            unbindService();
+        }
+        mThread.quit();
+        getContext().unregisterReceiver(mReceiver);
+    }
+
+    public void testSync() {
+        syncWithHandler();
+    }
+
+    public void testBind() {
+        bindService();
+        waitForCallback("onCreate");
+    }
+
+    public void testUnbind() {
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+    }
+
+    public void testTileServiceCallbacks() {
+        bindService();
+        waitForCallback("onCreate");
+
+        mStateManager.onTileAdded();
+        waitForCallback("onTileAdded");
+        mStateManager.onStartListening();
+        waitForCallback("onStartListening");
+        mStateManager.onClick(null);
+        waitForCallback("onClick");
+        mStateManager.onStopListening();
+        waitForCallback("onStopListening");
+        mStateManager.onTileRemoved();
+        waitForCallback("onTileRemoved");
+
+        unbindService();
+    }
+
+    public void testAddedBeforeBind() {
+        mStateManager.onTileAdded();
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+    }
+
+    public void testListeningBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+        waitForCallback("onStartListening");
+    }
+
+    public void testClickBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onTileAdded");
+        waitForCallback("onStartListening");
+        waitForCallback("onClick");
+    }
+
+    public void testListeningNotListeningBeforeBind() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onStopListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+        assertFalse(mCallbacks.contains("onStartListening"));
+    }
+
+    public void testNoClickOfNotListeningAnymore() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+        mStateManager.onClick(null);
+        mStateManager.onStopListening();
+
+        bindService();
+        waitForCallback("onCreate");
+        unbindService();
+        waitForCallback("onDestroy");
+        assertFalse(mCallbacks.contains("onClick"));
+    }
+
+    public void testComponentEnabling() {
+        mStateManager.onTileAdded();
+        mStateManager.onStartListening();
+
+        PackageManager pm = getContext().getPackageManager();
+        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
+
+        bindService();
+        assertTrue(mStateManager.mReceiverRegistered);
+
+        pm.setComponentEnabledSetting(new ComponentName(getContext(), FakeTileService.class),
+                PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
+        waitForCallback("onCreate");
+    }
+
+    public void testKillProcess() {
+        mStateManager.onStartListening();
+        bindService();
+        waitForCallback("onCreate");
+        waitForCallback("onStartListening");
+
+        getContext().sendBroadcast(new Intent(FakeTileService.ACTION_KILL));
+
+        waitForCallback("onCreate");
+        waitForCallback("onStartListening");
+    }
+
+    private void bindService() {
+        mBound = true;
+        mStateManager.setBindService(true);
+    }
+
+    private void unbindService() {
+        mBound = false;
+        mStateManager.setBindService(false);
+    }
+
+    private void waitForCallback(String callback) {
+        for (int i = 0; i < 25; i++) {
+            if (mCallbacks.contains(callback)) {
+                mCallbacks.remove(callback);
+                return;
+            }
+            synchronized (mBroadcastLock) {
+                try {
+                    mBroadcastLock.wait(500);
+                } catch (InterruptedException e) {
+                }
+            }
+        }
+        if (mCallbacks.contains(callback)) {
+            mCallbacks.remove(callback);
+            return;
+        }
+        fail("Didn't receive callback: " + callback);
+    }
+
+    private void syncWithHandler() {
+        final Object lock = new Object();
+        synchronized (lock) {
+            mHandler.post(new Runnable() {
+                @Override
+                public void run() {
+                    synchronized (lock) {
+                        lock.notify();
+                    }
+                }
+            });
+            try {
+                lock.wait(5000);
+            } catch (InterruptedException e) {
+            }
+        }
+    }
+
+    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            mCallbacks.add(intent.getStringExtra(EXTRA_CALLBACK));
+            synchronized (mBroadcastLock) {
+                mBroadcastLock.notify();
+            }
+        }
+    };
+
+    public static class FakeTileService extends Service {
+        public static final String ACTION_KILL = "com.android.systemui.test.KILL";
+
+        @Override
+        public IBinder onBind(Intent intent) {
+            return new IQSTileService.Stub() {
+
+                @Override
+                public void setQSService(IQSService service) {
+
+                }
+
+                @Override
+                public void setQSTile(Tile tile) throws RemoteException {
+                }
+
+                @Override
+                public void onTileAdded() throws RemoteException {
+                    sendCallback("onTileAdded");
+                }
+
+                @Override
+                public void onTileRemoved() throws RemoteException {
+                    sendCallback("onTileRemoved");
+                }
+
+                @Override
+                public void onStartListening() throws RemoteException {
+                    sendCallback("onStartListening");
+                }
+
+                @Override
+                public void onStopListening() throws RemoteException {
+                    sendCallback("onStopListening");
+                }
+
+                @Override
+                public void onClick(IBinder iBinder) throws RemoteException {
+                    sendCallback("onClick");
+                }
+            };
+        }
+
+        @Override
+        public void onCreate() {
+            super.onCreate();
+            registerReceiver(mReceiver, new IntentFilter(ACTION_KILL));
+            sendCallback("onCreate");
+        }
+
+        @Override
+        public void onDestroy() {
+            super.onDestroy();
+            unregisterReceiver(mReceiver);
+            sendCallback("onDestroy");
+        }
+
+        private void sendCallback(String callback) {
+            Log.d("TileLifecycleManager", "Relaying: " + callback);
+            sendBroadcast(new Intent(TILE_UPDATE_BROADCAST)
+                    .putExtra(EXTRA_CALLBACK, callback));
+        }
+
+        private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
+            @Override
+            public void onReceive(Context context, Intent intent) {
+                if (ACTION_KILL.equals(intent.getAction())) {
+                    Process.killProcess(Process.myPid());
+                }
+            }
+        };
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
new file mode 100644
index 0000000..4586c28
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServiceManagerTests.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.os.Handler;
+import android.os.HandlerThread;
+import android.service.quicksettings.TileService;
+import com.android.systemui.SysuiTestCase;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+public class TileServiceManagerTests extends SysuiTestCase {
+
+    private TileServices mTileServices;
+    private TileLifecycleManager mTileLifecycle;
+    private HandlerThread mThread;
+    private Handler mHandler;
+    private TileServiceManager mTileServiceManager;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mThread = new HandlerThread("TestThread");
+        mThread.start();
+        mHandler = new Handler(mThread.getLooper());
+        mTileServices = Mockito.mock(TileServices.class);
+        Mockito.when(mTileServices.getContext()).thenReturn(mContext);
+        mTileLifecycle = Mockito.mock(TileLifecycleManager.class);
+        ComponentName componentName = new ComponentName(mContext,
+                TileServiceManagerTests.class);
+        Mockito.when(mTileLifecycle.getComponent()).thenReturn(componentName);
+        mContext.getSharedPreferences(TileServiceManager.PREFS_FILE, 0).edit()
+                .putInt(componentName.flattenToString(), TileService.TILE_MODE_PASSIVE).commit();
+        mTileServiceManager = new TileServiceManager(mTileServices, mHandler, mTileLifecycle);
+    }
+
+    @Override
+    protected void tearDown() throws Exception {
+        super.tearDown();
+        mThread.quit();
+    }
+
+    public void testSetBindRequested() {
+        // Request binding.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setLastUpdate(0);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+        assertEquals(5, mTileServiceManager.getBindPriority());
+
+        // Verify same state doesn't trigger recalculating for no reason.
+        mTileServiceManager.setBindRequested(true);
+        Mockito.verify(mTileServices, Mockito.times(2)).recalculateBindAllowance();
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(5);
+        Mockito.verify(mTileServices, Mockito.times(3)).recalculateBindAllowance();
+        assertEquals(Integer.MIN_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    public void testPendingClickPriority() {
+        Mockito.when(mTileLifecycle.hasPendingClick()).thenReturn(true);
+        mTileServiceManager.calculateBindPriority(0);
+        assertEquals(Integer.MAX_VALUE, mTileServiceManager.getBindPriority());
+    }
+
+    public void testBind() {
+        // Trigger binding requested and allowed.
+        mTileServiceManager.setBindRequested(true);
+        mTileServiceManager.setBindAllowed(true);
+
+        ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(1)).setBindService(captor.capture());
+        assertTrue((boolean) captor.getValue());
+
+        mTileServiceManager.setBindRequested(false);
+        mTileServiceManager.calculateBindPriority(0);
+        // Priority shouldn't disappear after the request goes away if we just bound, instead
+        // it sticks around to avoid thrashing a bunch of processes.
+        assertEquals(Integer.MAX_VALUE - 1, mTileServiceManager.getBindPriority());
+
+        mTileServiceManager.setBindAllowed(false);
+        captor = ArgumentCaptor.forClass(Boolean.class);
+        Mockito.verify(mTileLifecycle, Mockito.times(2)).setBindService(captor.capture());
+        assertFalse((boolean) captor.getValue());
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
new file mode 100644
index 0000000..7a3ce87
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/external/TileServicesTests.java
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+package com.android.systemui.qs.external;
+
+import android.content.ComponentName;
+import android.os.Looper;
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.phone.QSTileHost;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mockito;
+
+import java.util.ArrayList;
+
+public class TileServicesTests extends SysuiTestCase {
+    private static int NUM_FAKES = TileServices.DEFAULT_MAX_BOUND * 2;
+
+    private TileServices mTileService;
+    private ArrayList<TileServiceManager> mManagers;
+
+    @Override
+    protected void setUp() throws Exception {
+        super.setUp();
+        mManagers = new ArrayList<>();
+        QSTileHost host = new QSTileHost(mContext, null, null, null, null, null, null, null, null,
+                null, null, null, null, null, null);
+        mTileService = new TestTileServices(host, Looper.myLooper());
+    }
+
+    public void testRecalculateBindAllowance() {
+        // Add some fake tiles.
+        for (int i = 0; i < NUM_FAKES; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        assertEquals(NUM_FAKES, mManagers.size());
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.when(mManagers.get(i).getBindPriority()).thenReturn(i);
+        }
+        mTileService.recalculateBindAllowance();
+        for (int i = 0; i < NUM_FAKES; i++) {
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).calculateBindPriority(
+                    Mockito.anyLong());
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.DEFAULT_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    public void testSetMemoryPressure() {
+        testRecalculateBindAllowance();
+        mTileService.setMemoryPressure(true);
+
+        for (int i = 0; i < NUM_FAKES; i++) {
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(2)).setBindAllowed(captor.capture());
+
+            assertEquals("" + i + "th service", i >= (NUM_FAKES - TileServices.REDUCED_MAX_BOUND),
+                    (boolean) captor.getValue());
+        }
+    }
+
+    public void testCalcFew() {
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            mTileService.getTileWrapper(Mockito.mock(CustomTile.class));
+        }
+        mTileService.recalculateBindAllowance();
+
+        for (int i = 0; i < TileServices.DEFAULT_MAX_BOUND - 1; i++) {
+            // Shouldn't get bind prioirities calculated when there are less than the max services.
+            Mockito.verify(mManagers.get(i), Mockito.never()).calculateBindPriority(
+                    Mockito.anyLong());
+
+            // All should be bound since there are less than the max services.
+            ArgumentCaptor<Boolean> captor = ArgumentCaptor.forClass(Boolean.class);
+            Mockito.verify(mManagers.get(i), Mockito.times(1)).setBindAllowed(captor.capture());
+
+            assertTrue(captor.getValue());
+        }
+    }
+
+    private class TestTileServices extends TileServices {
+        public TestTileServices(QSTileHost host, Looper looper) {
+            super(host, looper);
+        }
+
+        @Override
+        protected TileServiceManager onCreateTileService(ComponentName component) {
+            TileServiceManager manager = Mockito.mock(TileServiceManager.class);
+            mManagers.add(manager);
+            return manager;
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 3e8dc4e..15d0fc4 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -244,6 +244,7 @@
 
 import static android.Manifest.permission.INTERACT_ACROSS_USERS;
 import static android.Manifest.permission.INTERACT_ACROSS_USERS_FULL;
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
 import static android.Manifest.permission.START_TASKS_FROM_RECENTS;
 import static android.app.ActivityManager.RESIZE_MODE_PRESERVE_WINDOW;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
@@ -257,6 +258,7 @@
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.provider.Settings.Global.ALWAYS_FINISH_ACTIVITIES;
 import static android.provider.Settings.Global.DEBUG_APP;
+import static android.provider.Settings.Global.DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES;
 import static android.provider.Settings.Global.DEVELOPMENT_FORCE_RTL;
 import static android.provider.Settings.Global.WAIT_FOR_DEBUGGER;
@@ -1445,6 +1447,7 @@
     static final int SYSTEM_USER_UNLOCK_MSG = 61;
     static final int LOG_STACK_STATE = 62;
     static final int VR_MODE_CHANGE_MSG = 63;
+    static final int NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG = 64;
 
     static final int FIRST_ACTIVITY_STACK_MSG = 100;
     static final int FIRST_BROADCAST_QUEUE_MSG = 200;
@@ -1998,9 +2001,7 @@
             }
             case NOTIFY_TASK_STACK_CHANGE_LISTENERS_MSG: {
                 synchronized (ActivityManagerService.this) {
-                    int i = mTaskStackListeners.beginBroadcast();
-                    while (i > 0) {
-                        i--;
+                    for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
                         try {
                             // Make a one-way callback to the listener
                             mTaskStackListeners.getBroadcastItem(i).onTaskStackChanged();
@@ -2012,6 +2013,20 @@
                 }
                 break;
             }
+            case NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG: {
+                synchronized (ActivityManagerService.this) {
+                    for (int i = mTaskStackListeners.beginBroadcast() - 1; i >= 0; i--) {
+                        try {
+                            // Make a one-way callback to the listener
+                            mTaskStackListeners.getBroadcastItem(i).onActivityPinned();
+                        } catch (RemoteException e){
+                            // Handled by the RemoteCallbackList
+                        }
+                    }
+                    mTaskStackListeners.finishBroadcast();
+                }
+                break;
+            }
             case NOTIFY_CLEARTEXT_NETWORK_MSG: {
                 final int uid = msg.arg1;
                 final byte[] firstPacket = (byte[]) msg.obj;
@@ -2743,9 +2758,15 @@
         return mAppBindArgs;
     }
 
-    final void setFocusedActivityLocked(ActivityRecord r, String reason) {
+    boolean setFocusedActivityLocked(ActivityRecord r, String reason) {
         if (r == null || mFocusedActivity == r) {
-            return;
+            return false;
+        }
+
+        if (!r.isFocusable()) {
+            if (DEBUG_FOCUS) Slog.d(TAG_FOCUS,
+                    "setFocusedActivityLocked: unfocusable r=" + r);
+            return false;
         }
 
         if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "setFocusedActivityLocked: r=" + r);
@@ -2783,7 +2804,7 @@
                 finishVoiceTask(last.task.voiceSession);
             }
         }
-        if (mStackSupervisor.setFocusedStack(r, reason + " setFocusedActivity")) {
+        if (mStackSupervisor.moveActivityStackToFront(r, reason + " setFocusedActivity")) {
             mWindowManager.setFocusedApp(r.appToken, true);
         }
         applyUpdateLockStateLocked(r);
@@ -2799,23 +2820,35 @@
                 mFocusedActivity == null ? -1 : mFocusedActivity.userId,
                 mFocusedActivity == null ? "NULL" : mFocusedActivity.shortComponentName,
                 reason);
+        return true;
     }
 
-    final void clearFocusedActivity(ActivityRecord r) {
-        if (mFocusedActivity == r) {
-            ActivityStack stack = mStackSupervisor.getFocusedStack();
-            if (stack != null) {
-                ActivityRecord top = stack.topActivity();
-                if (top != null && top.userId != mLastFocusedUserId) {
-                    mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
-                    mHandler.sendMessage(mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG,
-                                    top.userId, 0));
-                    mLastFocusedUserId = top.userId;
-                }
-            }
-            mFocusedActivity = null;
-            EventLogTags.writeAmFocusedActivity(-1, "NULL", "clearFocusedActivity");
+    final void resetFocusedActivityIfNeededLocked(ActivityRecord goingAway) {
+        if (mFocusedActivity != goingAway) {
+            return;
         }
+
+        final ActivityStack focusedStack = mStackSupervisor.getFocusedStack();
+        if (focusedStack != null) {
+            final ActivityRecord top = focusedStack.topActivity();
+            if (top != null && top.userId != mLastFocusedUserId) {
+                mHandler.removeMessages(FOREGROUND_PROFILE_CHANGED_MSG);
+                mHandler.sendMessage(
+                        mHandler.obtainMessage(FOREGROUND_PROFILE_CHANGED_MSG, top.userId, 0));
+                mLastFocusedUserId = top.userId;
+            }
+        }
+
+        // Try to move focus to another activity if possible.
+        if (setFocusedActivityLocked(
+                focusedStack.topRunningActivityLocked(), "resetFocusedActivityIfNeeded")) {
+            return;
+        }
+
+        if (DEBUG_FOCUS) Slog.d(TAG_FOCUS, "resetFocusedActivityIfNeeded: Setting focus to NULL "
+                + "prev mFocusedActivity=" + mFocusedActivity + " goingAway=" + goingAway);
+        mFocusedActivity = null;
+        EventLogTags.writeAmFocusedActivity(-1, "NULL", "resetFocusedActivityIfNeeded");
     }
 
     @Override
@@ -2827,7 +2860,7 @@
                 ActivityRecord r = stack.topRunningActivityLocked();
                 if (r != null) {
                     setFocusedActivityLocked(r, "setFocusedStack");
-                    mStackSupervisor.resumeTopActivitiesLocked(stack, null, null);
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -2844,7 +2877,7 @@
                     ActivityRecord r = task.topRunningActivityLocked();
                     if (r != null) {
                         setFocusedActivityLocked(r, "setFocusedTask");
-                        mStackSupervisor.resumeTopActivitiesLocked(task.stack, null, null);
+                        mStackSupervisor.resumeFocusedStackTopActivityLocked();
                     }
                 }
             }
@@ -2856,7 +2889,8 @@
     /** Sets the task stack listener that gets callbacks when a task stack changes. */
     @Override
     public void registerTaskStackListener(ITaskStackListener listener) throws RemoteException {
-        synchronized (ActivityManagerService.this) {
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "registerTaskStackListener()");
+        synchronized (this) {
             if (listener != null) {
                 mTaskStackListeners.register(listener);
             }
@@ -3590,7 +3624,7 @@
     Intent getHomeIntent() {
         Intent intent = new Intent(mTopAction, mTopData != null ? Uri.parse(mTopData) : null);
         intent.setComponent(mTopComponent);
-        intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         if (mFactoryTest != FactoryTest.FACTORY_TEST_LOW_LEVEL) {
             intent.addCategory(Intent.CATEGORY_HOME);
         }
@@ -4342,7 +4376,7 @@
     }
 
     @Override
-    public final int startActivityFromRecents(int taskId, int launchStackId, Bundle bOptions) {
+    public final int startActivityFromRecents(int taskId, Bundle bOptions) {
         if (checkCallingPermission(START_TASKS_FROM_RECENTS) != PackageManager.PERMISSION_GRANTED) {
             String msg = "Permission Denial: startActivityFromRecents called without " +
                     START_TASKS_FROM_RECENTS;
@@ -4351,24 +4385,28 @@
         }
         final long origId = Binder.clearCallingIdentity();
         try {
-            return startActivityFromRecentsInner(taskId, launchStackId, bOptions);
+            return startActivityFromRecentsInner(taskId, bOptions);
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
     }
 
-    final int startActivityFromRecentsInner(int taskId, int launchStackId, Bundle bOptions) {
+    final int startActivityFromRecentsInner(int taskId, Bundle bOptions) {
         final TaskRecord task;
         final int callingUid;
         final String callingPackage;
         final Intent intent;
         final int userId;
         synchronized (this) {
+            final ActivityOptions activityOptions = (bOptions != null)
+                    ? new ActivityOptions(bOptions) : null;
+            final int launchStackId = (activityOptions != null)
+                    ? activityOptions.getLaunchStackId() : INVALID_STACK_ID;
+
             if (launchStackId == HOME_STACK_ID) {
                 throw new IllegalArgumentException("startActivityFromRecentsInner: Task "
                         + taskId + " can't be launch in the home stack.");
             }
-
             task = mStackSupervisor.anyTaskForIdLocked(taskId, RESTORE_FROM_RECENTS, launchStackId);
             if (task == null) {
                 throw new IllegalArgumentException(
@@ -4376,10 +4414,9 @@
             }
 
             if (launchStackId != INVALID_STACK_ID) {
-                if (launchStackId == DOCKED_STACK_ID && bOptions != null) {
-                    ActivityOptions activityOptions = new ActivityOptions(bOptions);
-                    mWindowManager.setDockedStackCreateState(activityOptions.getDockCreateMode(),
-                            null /* initialBounds */);
+                if (launchStackId == DOCKED_STACK_ID && activityOptions != null) {
+                    mWindowManager.setDockedStackCreateState(
+                            activityOptions.getDockCreateMode(), null /* initialBounds */);
                 }
                 if (task.stack.mStackId != launchStackId) {
                     mStackSupervisor.moveTaskToStackLocked(
@@ -4388,7 +4425,10 @@
                 }
             }
 
-            if (task.getRootActivity() != null) {
+            // If the user must confirm credentials (e.g. when first launching a work app and the
+            // Work Challenge is present) let startActivityInPackage handle the intercepting.
+            if (!mUserController.shouldConfirmCredentials(task.userId)
+                    && task.getRootActivity() != null) {
                 moveTaskToFrontLocked(task.taskId, 0, bOptions);
                 return ActivityManager.START_TASK_TO_FRONT;
             }
@@ -4473,7 +4513,7 @@
             if (config != null) {
                 r.frozenBeforeDestroy = true;
                 if (!updateConfigurationLocked(config, r, false)) {
-                    mStackSupervisor.resumeTopActivitiesLocked();
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
             Binder.restoreCallingIdentity(origId);
@@ -4811,12 +4851,11 @@
             finishInstrumentationLocked(app, Activity.RESULT_CANCELED, info);
         }
 
-        if (!restarting && hasVisibleActivities && !mStackSupervisor.resumeTopActivitiesLocked()) {
-            // If there was nothing to resume, and we are not already
-            // restarting this process, but there is a visible activity that
-            // is hosted by the process...  then make sure all visible
-            // activities are running, taking care of restarting this
-            // process.
+        if (!restarting && hasVisibleActivities
+                && !mStackSupervisor.resumeFocusedStackTopActivityLocked()) {
+            // If there was nothing to resume, and we are not already restarting this process, but
+            // there is a visible activity that is hosted by the process...  then make sure all
+            // visible activities are running, taking care of restarting this process.
             mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         }
     }
@@ -5873,7 +5912,7 @@
         // Clean-up disabled activities.
         if (mStackSupervisor.finishDisabledPackageActivitiesLocked(
                 packageName, disabledClasses, true, false, userId) && mBooted) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
             mStackSupervisor.scheduleIdleLocked();
         }
 
@@ -6061,7 +6100,7 @@
                 }
             }
             if (mBooted) {
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 mStackSupervisor.scheduleIdleLocked();
             }
         }
@@ -6736,6 +6775,15 @@
     }
 
     @Override
+    public final void activityRelaunched(IBinder token) {
+        final long origId = Binder.clearCallingIdentity();
+        synchronized (this) {
+            mStackSupervisor.activityRelaunchedLocked(token);
+        }
+        Binder.restoreCallingIdentity(origId);
+    }
+
+    @Override
     public void reportSizeConfigurations(IBinder token, int[] horizontalSizeConfiguration,
             int[] verticalSizeConfigurations, int[] smallestSizeConfigurations) {
         if (DEBUG_CONFIGURATION) Slog.v(TAG, "Report configuration: " + token + " "
@@ -7257,7 +7305,7 @@
                             + "Can't find activity for token=" + token);
                 }
 
-                if (!r.info.supportsPip) {
+                if (!r.supportsPictureInPicture()) {
                     throw new IllegalArgumentException("enterPictureInPictureMode: "
                             + "Picture-In-Picture not supported for r=" + r);
                 }
@@ -8994,15 +9042,14 @@
                 task.mResizeable = resizeable;
                 mWindowManager.setTaskResizeable(taskId, resizeable);
                 mStackSupervisor.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
         }
     }
 
     @Override
     public void resizeTask(int taskId, Rect bounds, int resizeMode) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "resizeTask()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeTask()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9052,8 +9099,7 @@
 
     @Override
     public Rect getTaskBounds(int taskId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getTaskBounds()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getTaskBounds()");
         long ident = Binder.clearCallingIdentity();
         Rect rect = new Rect();
         try {
@@ -9355,8 +9401,7 @@
     @Override
     public IActivityContainer createVirtualActivityContainer(IBinder parentActivityToken,
             IActivityContainerCallback callback) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "createActivityContainer()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createActivityContainer()");
         synchronized (this) {
             if (parentActivityToken == null) {
                 throw new IllegalArgumentException("parent token must not be null");
@@ -9374,8 +9419,7 @@
 
     @Override
     public void deleteActivityContainer(IActivityContainer container) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "deleteActivityContainer()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "deleteActivityContainer()");
         synchronized (this) {
             mStackSupervisor.deleteActivityContainer(container);
         }
@@ -9383,8 +9427,7 @@
 
     @Override
     public IActivityContainer createStackOnDisplay(int displayId) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "createStackOnDisplay()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "createStackOnDisplay()");
         synchronized (this) {
             final int stackId = mStackSupervisor.getNextStackId();
             final ActivityStack stack =
@@ -9444,8 +9487,7 @@
 
     @Override
     public void moveTaskToStack(int taskId, int stackId, boolean toTop) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTaskToStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToStack()");
         if (stackId == HOME_STACK_ID) {
             throw new IllegalArgumentException(
                     "moveTaskToStack: Attempt to move task " + taskId + " to home stack");
@@ -9480,8 +9522,7 @@
     @Override
     public void moveTaskToDockedStack(int taskId, int createMode, boolean toTop, boolean animate,
             Rect initialBounds) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTaskToDockedStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTaskToDockedStack()");
         synchronized (this) {
             long ident = Binder.clearCallingIdentity();
             try {
@@ -9507,8 +9548,7 @@
      */
     @Override
     public boolean moveTopActivityToPinnedStack(int stackId, Rect bounds) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTopActivityToPinnedStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTopActivityToPinnedStack()");
         synchronized (this) {
             if (!mSupportsPictureInPicture) {
                 throw new IllegalStateException("moveTopActivityToPinnedStack:"
@@ -9526,13 +9566,31 @@
 
     @Override
     public void resizeStack(int stackId, Rect bounds, boolean allowResizeInDockedMode) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "resizeStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "resizeStack()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
                 mStackSupervisor.resizeStackLocked(
-                        stackId, bounds, !PRESERVE_WINDOWS, allowResizeInDockedMode);
+                        stackId, bounds, null /* tempTaskBounds */, null /* tempTaskInsetBounds */,
+                        !PRESERVE_WINDOWS, allowResizeInDockedMode);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
+        }
+    }
+
+    @Override
+    public void resizeDockedStack(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds) {
+        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
+                "resizeDockedStack()");
+        long ident = Binder.clearCallingIdentity();
+        try {
+            synchronized (this) {
+                mStackSupervisor.resizeDockedStackLocked(dockedBounds, tempDockedTaskBounds,
+                        tempDockedTaskInsetBounds, tempOtherTaskBounds, tempOtherTaskInsetBounds,
+                        PRESERVE_WINDOWS);
             }
         } finally {
             Binder.restoreCallingIdentity(ident);
@@ -9541,8 +9599,7 @@
 
     @Override
     public void positionTaskInStack(int taskId, int stackId, int position) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "positionTaskInStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "positionTaskInStack()");
         if (stackId == HOME_STACK_ID) {
             throw new IllegalArgumentException(
                     "positionTaskInStack: Attempt to change the position of task "
@@ -9563,8 +9620,7 @@
 
     @Override
     public List<StackInfo> getAllStackInfos() {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getAllStackInfos()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getAllStackInfos()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9577,8 +9633,7 @@
 
     @Override
     public StackInfo getStackInfo(int stackId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackInfo()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9591,8 +9646,7 @@
 
     @Override
     public boolean isInHomeStack(int taskId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "getStackInfo()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "getStackInfo()");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9706,8 +9760,7 @@
 
     @Override
     public void startLockTaskModeOnCurrent() throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "startLockTaskModeOnCurrent");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "startLockTaskModeOnCurrent");
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
@@ -9759,8 +9812,7 @@
 
     @Override
     public void stopLockTaskModeOnCurrent() throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "stopLockTaskModeOnCurrent");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "stopLockTaskModeOnCurrent");
         long ident = Binder.clearCallingIdentity();
         try {
             stopLockTaskMode();
@@ -9802,7 +9854,7 @@
             ParceledListSlice<ProviderInfo> slice = AppGlobals.getPackageManager()
                     .queryContentProviders(app.processName, app.uid,
                             STOCK_PM_FLAGS | PackageManager.GET_URI_PERMISSION_PATTERNS
-                                    | PackageManager.MATCH_ENCRYPTION_DEFAULT);
+                                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING);
             providers = slice != null ? slice.getList() : null;
         } catch (RemoteException ex) {
         }
@@ -11033,6 +11085,12 @@
         mHandler.sendMessageDelayed(nmsg, NOTIFY_TASK_STACK_CHANGE_LISTENERS_DELAY);
     }
 
+    /** Notifies all listeners when an Activity is pinned. */
+    void notifyActivityPinnedLocked() {
+        mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
+        mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG).sendToTarget();
+    }
+
     @Override
     public void notifyCleartextNetwork(int uid, byte[] firstPacket) {
         mHandler.obtainMessage(NOTIFY_CLEARTEXT_NETWORK_MSG, uid, 0, firstPacket).sendToTarget();
@@ -12149,7 +12207,9 @@
     private void retrieveSettings() {
         final ContentResolver resolver = mContext.getContentResolver();
         final boolean freeformWindowManagement =
-                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT);
+                mContext.getPackageManager().hasSystemFeature(FEATURE_FREEFORM_WINDOW_MANAGEMENT)
+                        || Settings.Global.getInt(
+                                resolver, DEVELOPMENT_ENABLE_FREEFORM_WINDOWS_SUPPORT, 0) != 0;
         final boolean supportsPictureInPicture =
                 mContext.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE);
 
@@ -12158,9 +12218,8 @@
         final boolean alwaysFinishActivities =
                 Settings.Global.getInt(resolver, ALWAYS_FINISH_ACTIVITIES, 0) != 0;
         final boolean forceRtl = Settings.Global.getInt(resolver, DEVELOPMENT_FORCE_RTL, 0) != 0;
-        final int defaultForceResizable = Build.IS_DEBUGGABLE ? 1 : 0;
         final boolean forceResizable = Settings.Global.getInt(
-                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, defaultForceResizable) != 0;
+                resolver, DEVELOPMENT_FORCE_RESIZABLE_ACTIVITIES, 0) != 0;
         // Transfer any global setting for forcing RTL layout, into a System Property
         SystemProperties.set(DEVELOPMENT_FORCE_RTL, forceRtl ? "1":"0");
 
@@ -12603,7 +12662,7 @@
             } finally {
                 Binder.restoreCallingIdentity(ident);
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
             mUserController.sendUserSwitchBroadcastsLocked(-1, currentUserId);
         }
     }
@@ -12714,10 +12773,10 @@
                 // annoy the user repeatedly.  Unless it is persistent, since those
                 // processes run critical code.
                 removeProcessLocked(app, false, false, "crash");
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return false;
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } else {
             mStackSupervisor.finishTopRunningActivityLocked(app, reason);
         }
@@ -17010,7 +17069,7 @@
     private List<ResolveInfo> collectReceiverComponents(Intent intent, String resolvedType,
             int callingUid, int[] users) {
         // TODO: come back and remove this assumption to triage all broadcasts
-        int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_ENCRYPTION_DEFAULT;
+        int pmFlags = STOCK_PM_FLAGS | PackageManager.MATCH_DEBUG_TRIAGED_MISSING;
 
         List<ResolveInfo> receivers = null;
         try {
@@ -17933,8 +17992,7 @@
 
     @Override
     public void suppressResizeConfigChanges(boolean suppress) throws RemoteException {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "suppressResizeConfigChanges()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "suppressResizeConfigChanges()");
         synchronized (this) {
             mSuppressResizeConfigChanges = suppress;
         }
@@ -17942,8 +18000,7 @@
 
     @Override
     public void moveTasksToFullscreenStack(int fromStackId) {
-        enforceCallingPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS,
-                "moveTasksToFullscreenStack()");
+        enforceCallingPermission(MANAGE_ACTIVITY_STACKS, "moveTasksToFullscreenStack()");
         if (fromStackId == HOME_STACK_ID) {
             throw new IllegalArgumentException("You can't move tasks from the home stack.");
         }
@@ -18062,10 +18119,18 @@
                 EventLog.writeEvent(EventLogTags.CONFIGURATION_CHANGED, changes);
 
                 if (!initLocale && !values.getLocales().isEmpty() && values.userSetLocale) {
-                    if (mSupportedSystemLocales == null) {
-                        mSupportedSystemLocales = Resources.getSystem().getAssets().getLocales();
+                    final Locale locale;
+                    if (values.getLocales().size() == 1) {
+                        // This is an optimization to avoid the JNI call when the result of
+                        // getFirstMatch() does not depend on the supported locales.
+                        locale = values.getLocales().getPrimary();
+                    } else {
+                        if (mSupportedSystemLocales == null) {
+                            mSupportedSystemLocales =
+                                    Resources.getSystem().getAssets().getLocales();
+                        }
+                        locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
                     }
-                    final Locale locale = values.getLocales().getFirstMatch(mSupportedSystemLocales);
                     SystemProperties.set("persist.sys.locale", locale.toLanguageTag());
                     mHandler.sendMessage(mHandler.obtainMessage(SEND_LOCALE_TO_MOUNT_DAEMON_MSG,
                             locale));
@@ -20889,7 +20954,7 @@
         public void moveToFront() {
             checkCaller();
             // Will bring task to front if it already has a root activity.
-            startActivityFromRecentsInner(mTaskId, INVALID_STACK_ID, null);
+            startActivityFromRecentsInner(mTaskId, null);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/am/ActivityMetricsLogger.java b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
index 9680382..4101dde 100644
--- a/services/core/java/com/android/server/am/ActivityMetricsLogger.java
+++ b/services/core/java/com/android/server/am/ActivityMetricsLogger.java
@@ -26,7 +26,7 @@
     // Preallocated strings we are sending to tron, so we don't have to allocate a new one every
     // time we log.
     private static final String[] TRON_WINDOW_STATE_VARZ_STRINGS = {
-            "tron_varz_window_time_0", "tron_varz_window_time_1", "tron_varz_window_time_2"};
+            "window_time_0", "window_time_1", "window_time_2"};
 
     private int mWindowState = WINDOW_STATE_STANDARD;
     private long mLastLogTimeSecs;
diff --git a/services/core/java/com/android/server/am/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 4d9120b..4fb87c3 100755
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -16,7 +16,11 @@
 
 package com.android.server.am;
 
+import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.content.pm.ActivityInfo.FLAG_ALWAYS_FOCUSABLE;
+import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
+import static android.content.pm.ActivityInfo.FLAG_SUPPORTS_PICTURE_IN_PICTURE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SAVED_STATE;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
@@ -739,6 +743,22 @@
                         (intent.getFlags() & Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS) == 0);
     }
 
+    boolean isFocusable() {
+        return StackId.canReceiveKeys(task.stack.mStackId) || isAlwaysFocusable();
+    }
+
+    boolean isResizeable() {
+        return (info.flags & FLAG_RESIZEABLE) != 0;
+    }
+
+    boolean supportsPictureInPicture() {
+        return (info.flags & FLAG_SUPPORTS_PICTURE_IN_PICTURE) != 0;
+    }
+
+    boolean isAlwaysFocusable() {
+        return (info.flags & FLAG_ALWAYS_FOCUSABLE) != 0;
+    }
+
     void makeFinishingLocked() {
         if (!finishing) {
             if (task != null && task.stack != null
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 1492e23..8d9cb58 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -560,7 +560,7 @@
 
         // TODO(multi-display): Needs to also work if focus is moving to the non-home display.
         if (isOnHomeDisplay()) {
-            mStackSupervisor.setFocusStack(reason, this);
+            mStackSupervisor.setFocusStackUnchecked(reason, this);
         }
         if (task != null) {
             insertTaskAtTop(task, null);
@@ -572,6 +572,16 @@
         }
     }
 
+    boolean isFocusable() {
+        if (StackId.canReceiveKeys(mStackId)) {
+            return true;
+        }
+        // The stack isn't focusable. See if its top activity is focusable to force focus on the
+        // stack.
+        final ActivityRecord r = topRunningActivityLocked();
+        return r != null && r.isFocusable();
+    }
+
     final boolean isAttached() {
         return mStacks != null;
     }
@@ -917,7 +927,7 @@
         if (prev == null) {
             if (!resuming) {
                 Slog.wtf(TAG, "Trying to pause when nothing is resumed");
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
         }
@@ -1008,7 +1018,7 @@
             // pause, so just treat it as being paused now.
             if (DEBUG_PAUSE) Slog.v(TAG_PAUSE, "Activity not running, resuming next.");
             if (!resuming) {
-                mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             return false;
         }
@@ -1075,7 +1085,7 @@
             } else {
                 if (r.configDestroy) {
                     destroyActivityLocked(r, true, "stop-config");
-                    mStackSupervisor.resumeTopActivitiesLocked();
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 } else {
                     mStackSupervisor.updatePreviousProcessLocked(r);
                 }
@@ -1131,17 +1141,16 @@
         if (resumeNext) {
             final ActivityStack topStack = mStackSupervisor.getFocusedStack();
             if (!mService.isSleepingOrShuttingDown()) {
-                mStackSupervisor.resumeTopActivitiesLocked(topStack, prev, null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked(topStack, prev, null);
             } else {
                 mStackSupervisor.checkReadyForSleepLocked();
                 ActivityRecord top = topStack.topRunningActivityLocked();
                 if (top == null || (prev != null && top != prev)) {
-                    // If there are no more activities available to run,
-                    // do resume anyway to start something.  Also if the top
-                    // activity on the stack is not the just paused activity,
-                    // we need to go ahead and resume it to ensure we complete
-                    // an in-flight app switch.
-                    mStackSupervisor.resumeTopActivitiesLocked(topStack, null, null);
+                    // If there are no more activities available to run, do resume anyway to start
+                    // something. Also if the top activity on the stack is not the just paused
+                    // activity, we need to go ahead and resume it to ensure we complete an
+                    // in-flight app switch.
+                    mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -1296,7 +1305,7 @@
         return null;
     }
 
-    private ActivityStack getNextVisibleStackLocked() {
+    ActivityStack getNextFocusableStackLocked() {
         ArrayList<ActivityStack> stacks = mStacks;
         final ActivityRecord parent = mActivityContainer.mParentActivity;
         if (parent != null) {
@@ -1305,7 +1314,7 @@
         if (stacks != null) {
             for (int i = stacks.size() - 1; i >= 0; --i) {
                 ActivityStack stack = stacks.get(i);
-                if (stack != this && stack.isStackVisibleLocked()) {
+                if (stack != this && stack.isFocusable() && stack.isStackVisibleLocked()) {
                     return stack;
                 }
             }
@@ -1478,7 +1487,7 @@
         boolean aboveTop = top != null;
         final boolean stackInvisible = !isStackVisibleLocked();
         boolean behindFullscreenActivity = stackInvisible;
-        boolean noStackActivityResumed = (isInStackLocked(starting) == null);
+        boolean resumeNextActivity = isFocusable() && (isInStackLocked(starting) == null);
 
         for (int taskNdx = mTaskHistory.size() - 1; taskNdx >= 0; --taskNdx) {
             final TaskRecord task = mTaskHistory.get(taskNdx);
@@ -1509,18 +1518,18 @@
 
                     if (r.app == null || r.app.thread == null) {
                         if (makeVisibleAndRestartIfNeeded(starting, configChanges, isTop,
-                                noStackActivityResumed, r)) {
+                                resumeNextActivity, r)) {
                             if (activityNdx >= activities.size()) {
                                 // Record may be removed if its process needs to restart.
                                 activityNdx = activities.size() - 1;
                             } else {
-                                noStackActivityResumed = false;
+                                resumeNextActivity = false;
                             }
                         }
                     } else if (r.visible) {
                         // If this activity is already visible, then there is nothing to do here.
                         if (handleAlreadyVisible(r)) {
-                            noStackActivityResumed = false;
+                            resumeNextActivity = false;
                         }
                     } else {
                         makeVisible(starting, r);
@@ -1561,7 +1570,7 @@
     }
 
     private boolean makeVisibleAndRestartIfNeeded(ActivityRecord starting, int configChanges,
-            boolean isTop, boolean noStackActivityResumed, ActivityRecord r) {
+            boolean isTop, boolean andResume, ActivityRecord r) {
         // We need to make sure the app is running if it's the top, or it is just made visible from
         // invisible. If the app is already visible, it must have died while it was visible. In this
         // case, we'll show the dead window but will not restart the app. Otherwise we could end up
@@ -1578,7 +1587,7 @@
                 setVisible(r, true);
             }
             if (r != starting) {
-                mStackSupervisor.startSpecificActivityLocked(r, noStackActivityResumed, false);
+                mStackSupervisor.startSpecificActivityLocked(r, andResume, false);
                 return true;
             }
         }
@@ -1772,15 +1781,17 @@
      *
      * @param prev The previously resumed activity, for when in the process
      * of pausing; can be null to call from elsewhere.
+     * @param options Activity options.
      *
      * @return Returns true if something is being resumed, or false if
      * nothing happened.
+     *
+     * NOTE: It is not safe to call this method directly as it can cause an activity in a
+     *       non-focused stack to be resumed.
+     *       Use {@link ActivityStackSupervisor#resumeFocusedStackTopActivityLocked} to resume the
+     *       right activity for the current system state.
      */
-    final boolean resumeTopActivityLocked(ActivityRecord prev) {
-        return resumeTopActivityLocked(prev, null);
-    }
-
-    final boolean resumeTopActivityLocked(ActivityRecord prev, ActivityOptions options) {
+    boolean resumeTopActivityUncheckedLocked(ActivityRecord prev, ActivityOptions options) {
         if (mStackSupervisor.inResumeTopActivity) {
             // Don't even start recursing.
             return false;
@@ -1831,14 +1842,13 @@
         if (next == null) {
             // There are no more activities!
             final String reason = "noMoreActivities";
-            if (!mFullscreen) {
+            if (!mFullscreen && adjustFocusToNextFocusableStackLocked(reason)) {
                 // Try to move focus to the next visible stack with a running activity if this
                 // stack is not covering the entire screen.
-                final ActivityStack stack = getNextVisibleStackLocked();
-                if (adjustFocusToNextVisibleStackLocked(stack, reason)) {
-                    return mStackSupervisor.resumeTopActivitiesLocked(stack, prev, null);
-                }
+                return mStackSupervisor.resumeFocusedStackTopActivityLocked(
+                        mStackSupervisor.getFocusedStack(), prev, null);
             }
+
             // Let's just start up the Launcher...
             ActivityOptions.abort(options);
             if (DEBUG_STATES) Slog.d(TAG_STATES,
@@ -2870,7 +2880,7 @@
         final ActivityRecord next = topRunningActivityLocked();
         final String myReason = reason + " adjustFocus";
         if (next != r) {
-            if (next != null && StackId.keepFocusInStackIfPossible(mStackId)) {
+            if (next != null && StackId.keepFocusInStackIfPossible(mStackId) && isFocusable()) {
                 // For freeform, docked, and pinned stacks we always keep the focus within the
                 // stack as long as there is a running activity in the stack that we can adjust
                 // focus to.
@@ -2882,8 +2892,7 @@
                     // For non-fullscreen stack, we want to move the focus to the next visible
                     // stack to prevent the home screen from moving to the top and obscuring
                     // other visible stacks.
-                    if (!mFullscreen
-                            && adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                    if (!mFullscreen && adjustFocusToNextFocusableStackLocked(myReason)) {
                         return;
                     }
                     // Move the home stack to the top if this stack is fullscreen or there is no
@@ -2897,24 +2906,16 @@
             }
         }
 
-        final ActivityRecord top = mStackSupervisor.topRunningActivityLocked();
-        if (top != null) {
-            mService.setFocusedActivityLocked(top, myReason);
-        }
+        mService.setFocusedActivityLocked(mStackSupervisor.topRunningActivityLocked(), myReason);
     }
 
-    private boolean adjustFocusToNextVisibleStackLocked(ActivityStack inStack, String reason) {
-        final ActivityStack stack = (inStack != null) ? inStack : getNextVisibleStackLocked();
-        final String myReason = reason + " adjustFocusToNextVisibleStack";
+    private boolean adjustFocusToNextFocusableStackLocked(String reason) {
+        final ActivityStack stack = getNextFocusableStackLocked();
+        final String myReason = reason + " adjustFocusToNextFocusableStack";
         if (stack == null) {
             return false;
         }
-        final ActivityRecord top = stack.topRunningActivityLocked();
-        if (top == null) {
-            return false;
-        }
-        mService.setFocusedActivityLocked(top, myReason);
-        return true;
+        return mService.setFocusedActivityLocked(stack.topRunningActivityLocked(), myReason);
     }
 
     final void stopActivityLocked(ActivityRecord r) {
@@ -3224,7 +3225,7 @@
             r.makeFinishingLocked();
             boolean activityRemoved = destroyActivityLocked(r, true, "finish-imm");
             if (activityRemoved) {
-                mStackSupervisor.resumeTopActivitiesLocked();
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
             }
             if (DEBUG_CONTAINERS) Slog.d(TAG_CONTAINERS,
                     "destroyActivityLocked: finishCurrentActivityLocked r=" + r +
@@ -3237,7 +3238,7 @@
         if (DEBUG_ALL) Slog.v(TAG, "Enqueueing pending finish: " + r);
         mStackSupervisor.mFinishingActivities.add(r);
         r.resumeKeyDispatchingLocked();
-        mStackSupervisor.getFocusedStack().resumeTopActivityLocked(null);
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         return r;
     }
 
@@ -3395,7 +3396,7 @@
         if (mPausingActivity == r) {
             mPausingActivity = null;
         }
-        mService.clearFocusedActivity(r);
+        mService.resetFocusedActivityIfNeededLocked(r);
 
         r.configDestroy = false;
         r.frozenBeforeDestroy = false;
@@ -3526,7 +3527,7 @@
             }
         }
         if (activityRemoved) {
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3700,7 +3701,7 @@
                     removeActivityFromHistoryLocked(r, reason);
                 }
             }
-            mStackSupervisor.resumeTopActivitiesLocked();
+            mStackSupervisor.resumeFocusedStackTopActivityLocked();
         } finally {
             Binder.restoreCallingIdentity(origId);
         }
@@ -3738,7 +3739,7 @@
             setVisibleBehindActivity(null);
             mStackSupervisor.scheduleIdleTimeoutLocked(null);
         }
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
     }
 
     boolean hasVisibleBehindActivity() {
@@ -3953,7 +3954,7 @@
             updateTransitLocked(AppTransition.TRANSIT_TASK_TO_FRONT, options);
         }
 
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         EventLog.writeEvent(EventLogTags.AM_TASK_TO_FRONT, tr.userId, tr.taskId);
 
         if (VALIDATE_TOKENS) {
@@ -4016,7 +4017,7 @@
             if (fullscreenStack != null && fullscreenStack.hasVisibleBehindActivity()) {
                 final ActivityRecord visibleBehind = fullscreenStack.getVisibleBehindActivity();
                 mService.setFocusedActivityLocked(visibleBehind, "moveTaskToBack");
-                mStackSupervisor.resumeTopActivitiesLocked(fullscreenStack, null, null);
+                mStackSupervisor.resumeFocusedStackTopActivityLocked();
                 return true;
             }
         }
@@ -4071,7 +4072,7 @@
             return mStackSupervisor.resumeHomeStackTask(taskToReturnTo, null, "moveTaskToBack");
         }
 
-        mStackSupervisor.resumeTopActivitiesLocked();
+        mStackSupervisor.resumeFocusedStackTopActivityLocked();
         return true;
     }
 
@@ -4313,6 +4314,7 @@
             r.app.thread.scheduleRelaunchActivity(r.appToken, results, newIntents, changes,
                     !andResume, new Configuration(mService.mConfiguration),
                     new Configuration(r.task.mOverrideConfig), preserveWindow);
+            mStackSupervisor.activityRelaunchingLocked(r);
             // Note: don't need to call pauseIfSleepingLocked() here, because
             // the caller will only pass in 'andResume' if this activity is
             // currently resumed, which implies we aren't sleeping.
@@ -4661,7 +4663,7 @@
             // We only need to adjust focused stack if this stack is in focus.
             if (isOnHomeDisplay() && mStackSupervisor.isFocusedStack(this)) {
                 String myReason = reason + " leftTaskHistoryEmpty";
-                if (mFullscreen || !adjustFocusToNextVisibleStackLocked(null, myReason)) {
+                if (mFullscreen || !adjustFocusToNextFocusableStackLocked(myReason)) {
                     mStackSupervisor.moveHomeStackToFront(myReason);
                 }
             }
@@ -4734,10 +4736,7 @@
 
     private void postAddTask(TaskRecord task, ActivityStack prevStack) {
         if (prevStack != null) {
-            if (prevStack != this
-                    && (prevStack.mStackId == PINNED_STACK_ID || mStackId == PINNED_STACK_ID)) {
-                task.reportPictureInPictureModeChange();
-            }
+            task.reportPictureInPictureModeChangeIfNeeded(prevStack);
         } else if (task.voiceSession != null) {
             try {
                 task.voiceSession.taskStarted(task.intent, task.taskId);
@@ -4751,32 +4750,28 @@
         task.updateOverrideConfiguration(bounds);
         mWindowManager.addAppToken(task.mActivities.indexOf(r), r.appToken,
                 r.task.taskId, mStackId, r.info.screenOrientation, r.fullscreen,
-                (r.info.flags & ActivityInfo.FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId,
-                r.info.configChanges, task.voiceSession != null, r.mLaunchTaskBehind,
-                bounds, task.mOverrideConfig, !r.isHomeActivity());
+                (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) != 0, r.userId, r.info.configChanges,
+                task.voiceSession != null, r.mLaunchTaskBehind, bounds, task.mOverrideConfig,
+                !r.isHomeActivity(), r.isAlwaysFocusable());
         mWindowManager.setTaskResizeable(task.taskId, task.mResizeable);
         r.taskConfigOverride = task.mOverrideConfig;
     }
 
-    void setFocusAndResumeStateIfNeeded(
-            ActivityRecord r, boolean setFocus, boolean setResume, String reason) {
-        // If the activity had focus before move focus to this stack.
-        if (setFocus) {
-            // If the activity owns the last resumed activity, transfer that together,
-            // so that we don't resume the same activity again in the new stack.
-            // Apps may depend on onResume()/onPause() being called in pairs.
-            if (setResume) {
-                mResumedActivity = r;
-                // Move the stack in which we are placing the activity to the front. We don't use
-                // ActivityManagerService.setFocusedActivityLocked, because if the activity is
-                // already focused, the call will short-circuit and do nothing.
-                moveToFront(reason);
-            } else {
-                // We need to not only move the stack to the front, but also have the activity
-                // focused. This will achieve both goals.
-                mService.setFocusedActivityLocked(r, reason);
-            }
+    void moveToFrontAndResumeStateIfNeeded(
+            ActivityRecord r, boolean moveToFront, boolean setResume, String reason) {
+        if (!moveToFront) {
+            return;
         }
+
+        // If the activity owns the last resumed activity, transfer that together,
+        // so that we don't resume the same activity again in the new stack.
+        // Apps may depend on onResume()/onPause() being called in pairs.
+        if (setResume) {
+            mResumedActivity = r;
+        }
+        // Move the stack in which we are placing the activity to the front. The call will also
+        // make sure the activity focus is set.
+        moveToFront(reason);
     }
 
     /**
@@ -4800,8 +4795,11 @@
         r.setTask(task, null);
         task.addActivityToTop(r);
         setAppTask(r, task);
-        task.reportPictureInPictureModeChange();
-        setFocusAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        task.reportPictureInPictureModeChangeIfNeeded(prevStack);
+        moveToFrontAndResumeStateIfNeeded(r, wasFocused, wasResumed, "moveActivityToStack");
+        if (wasResumed) {
+            prevStack.mResumedActivity = null;
+        }
     }
 
     private void setAppTask(ActivityRecord r, TaskRecord task) {
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 32671acf..80a75ce 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -16,70 +16,6 @@
 
 package com.android.server.am;
 
-import static android.Manifest.permission.START_ANY_ACTIVITY;
-import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
-import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
-import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
-import static android.app.ActivityManager.RESIZE_MODE_FORCED;
-import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
-import static android.app.ActivityManager.StackId.HOME_STACK_ID;
-import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
-import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
-import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
-import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
-import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
-import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
-import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
-import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
-import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
-import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
-import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
-import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
-import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
-import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
-import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
-
 import android.Manifest;
 import android.app.Activity;
 import android.app.ActivityManager;
@@ -164,6 +100,70 @@
 import java.util.List;
 import java.util.Set;
 
+import static android.Manifest.permission.START_ANY_ACTIVITY;
+import static android.app.ActivityManager.LOCK_TASK_MODE_LOCKED;
+import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
+import static android.app.ActivityManager.LOCK_TASK_MODE_PINNED;
+import static android.app.ActivityManager.RESIZE_MODE_FORCED;
+import static android.app.ActivityManager.RESIZE_MODE_SYSTEM;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_DYNAMIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FIRST_STATIC_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.LAST_STATIC_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.pm.ActivityInfo.FLAG_SHOW_FOR_ALL_USERS;
+import static android.content.pm.PackageManager.PERMISSION_GRANTED;
+import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_ALL;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKSCREEN;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_CONTAINERS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_IDLE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_LOCKTASK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_PAUSE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RECENTS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_RELEASE;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STACK;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_STATES;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_SWITCH;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_TASKS;
+import static com.android.server.am.ActivityManagerDebugConfig.POSTFIX_VISIBLE_BEHIND;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
+import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.am.ActivityManagerService.FIRST_SUPERVISOR_STACK_MSG;
+import static com.android.server.am.ActivityRecord.APPLICATION_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.HOME_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityRecord.RECENTS_ACTIVITY_TYPE;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYED;
+import static com.android.server.am.ActivityStack.ActivityState.DESTROYING;
+import static com.android.server.am.ActivityStack.ActivityState.INITIALIZING;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSED;
+import static com.android.server.am.ActivityStack.ActivityState.PAUSING;
+import static com.android.server.am.ActivityStack.ActivityState.RESUMED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPED;
+import static com.android.server.am.ActivityStack.ActivityState.STOPPING;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_DONT_LOCK;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_LAUNCHABLE_PRIV;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_PINNABLE;
+import static com.android.server.am.TaskRecord.LOCK_TASK_AUTH_WHITELISTED;
+
 public final class ActivityStackSupervisor implements DisplayListener {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStackSupervisor" : TAG_AM;
     private static final String TAG_CONTAINERS = TAG + POSTFIX_CONTAINERS;
@@ -370,7 +370,7 @@
      */
     private LockTaskNotify mLockTaskNotify;
 
-    /** Used to keep resumeTopActivityLocked() from being entered recursively */
+    /** Used to keep resumeTopActivityUncheckedLocked() from being entered recursively */
     boolean inResumeTopActivity;
 
     // temp. rects used during resize calculation so we don't need to create a new object each time.
@@ -379,6 +379,7 @@
 
     private final SparseArray<Configuration> mTmpConfigs = new SparseArray<>();
     private final SparseArray<Rect> mTmpBounds = new SparseArray<>();
+    private final SparseArray<Rect> mTmpInsetBounds = new SparseArray<>();
 
     // The default minimal size that will be used if the activity doesn't specify its minimal size.
     // It will be calculated when the default display gets added.
@@ -389,6 +390,8 @@
 
     private final ActivityMetricsLogger mActivityMetricsLogger;
 
+    private final ResizeDockedStackTimeout mResizeDockedStackTimeout;
+
     static class FindTaskResult {
         ActivityRecord r;
         boolean matchedByRootAffinity;
@@ -432,6 +435,7 @@
         mRecentTasks = recentTasks;
         mHandler = new ActivityStackSupervisorHandler(mService.mHandler.getLooper());
         mActivityMetricsLogger = new ActivityMetricsLogger(this, mService.mContext);
+        mResizeDockedStackTimeout = new ResizeDockedStackTimeout(service, this, mHandler);
     }
 
     /**
@@ -492,8 +496,8 @@
                 calculateDefaultMinimalSizeOfResizeableTasks(activityDisplay);
             }
 
-            createStackOnDisplay(HOME_STACK_ID, Display.DEFAULT_DISPLAY, true);
-            mHomeStack = mFocusedStack = mLastFocusedStack = getStack(HOME_STACK_ID);
+            mHomeStack = mFocusedStack = mLastFocusedStack =
+                    getStack(HOME_STACK_ID, CREATE_IF_NEEDED, ON_TOP);
 
             mInputManagerInternal = LocalServices.getService(InputManagerInternal.class);
         }
@@ -537,16 +541,30 @@
         return stack == mHomeStack.mStacks.get((mHomeStack.mStacks.size() - 1));
     }
 
-    void setFocusStack(String reason, ActivityStack focusedStack) {
-        mLastFocusedStack = mFocusedStack;
-        mFocusedStack = focusedStack;
+    /** NOTE: Should only be called from {@link ActivityStack#moveToFront} */
+    void setFocusStackUnchecked(String reason, ActivityStack focusCandidate) {
+        if (!focusCandidate.isFocusable()) {
+            // The focus candidate isn't focusable. Move focus to the top stack that is focusable.
+            focusCandidate = focusCandidate.getNextFocusableStackLocked();
+        }
 
-        EventLogTags.writeAmFocusedStack(
-                mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
-                mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+        if (focusCandidate != mFocusedStack) {
+            mLastFocusedStack = mFocusedStack;
+            mFocusedStack = focusCandidate;
+
+            EventLogTags.writeAmFocusedStack(
+                    mCurrentUser, mFocusedStack == null ? -1 : mFocusedStack.getStackId(),
+                    mLastFocusedStack == null ? -1 : mLastFocusedStack.getStackId(), reason);
+        }
+
+        final ActivityRecord r = topRunningActivityLocked();
+        if (mService.mFocusedActivity != r) {
+            // The focus activity should always be the top activity in the focused stack.
+            // There will be chaos and anarchy if it isn't...
+            mService.setFocusedActivityLocked(r, reason + " setFocusStack");
+        }
 
         if (mService.mBooting || !mService.mBooted) {
-            final ActivityRecord r = topRunningActivityLocked();
             if (r != null && r.idle) {
                 checkFinishBootingLocked();
             }
@@ -591,12 +609,14 @@
 
         mHomeStack.moveHomeStackTaskToTop(homeStackTaskType);
         ActivityRecord r = getHomeActivity();
+        final String myReason = reason + " resumeHomeStackTask";
+
         // Only resume home activity if isn't finishing.
         if (r != null && !r.finishing) {
-            mService.setFocusedActivityLocked(r, reason);
-            return resumeTopActivitiesLocked(mHomeStack, prev, null);
+            mService.setFocusedActivityLocked(r, myReason);
+            return resumeFocusedStackTopActivityLocked(mHomeStack, prev, null);
         }
-        return mService.startHomeActivityLocked(mCurrentUser, reason);
+        return mService.startHomeActivityLocked(mCurrentUser, myReason);
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
@@ -893,7 +913,7 @@
         final ArrayList<ActivityStack> stacks = mHomeStack.mStacks;
         for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
             final ActivityStack stack = stacks.get(stackNdx);
-            if (stack != focusedStack && isFrontStack(stack)) {
+            if (stack != focusedStack && isFrontStack(stack) && stack.isFocusable()) {
                 r = stack.topRunningActivityLocked();
                 if (r != null) {
                     return r;
@@ -1148,14 +1168,12 @@
             // a resume.
             stack.minimalResumeActivityLocked(r);
         } else {
-            // This activity is not starting in the resumed state... which
-            // should look like we asked it to pause+stop (but remain visible),
-            // and it has done so and reported back the current icicle and
-            // other state.
+            // This activity is not starting in the resumed state... which should look like we asked
+            // it to pause+stop (but remain visible), and it has done so and reported back the
+            // current icicle and other state.
             if (DEBUG_STATES) Slog.v(TAG_STATES,
-                    "Moving to STOPPED: " + r + " (starting in stopped state)");
-            r.state = STOPPED;
-            r.stopped = true;
+                    "Moving to PAUSED: " + r + " (starting in paused state)");
+            r.state = PAUSED;
         }
 
         // Launch the new version setup screen if needed.  We do this -after-
@@ -1345,30 +1363,20 @@
         return ACTIVITY_RESTRICTION_NONE;
     }
 
-    boolean setFocusedStack(ActivityRecord r, String reason) {
+    boolean moveActivityStackToFront(ActivityRecord r, String reason) {
         if (r == null) {
             // Not sure what you are trying to do, but it is not going to work...
             return false;
         }
         final TaskRecord task = r.task;
         if (task == null || task.stack == null) {
-            Slog.w(TAG, "Can't set focus stack for r=" + r + " task=" + task);
+            Slog.w(TAG, "Can't move stack to front for r=" + r + " task=" + task);
             return false;
         }
         task.stack.moveToFront(reason, task);
         return true;
     }
 
-    Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
-        Rect newBounds = null;
-        if (options != null && (r.info.resizeable || (inTask != null && inTask.mResizeable))) {
-            if (canUseActivityOptionsLaunchBounds(options)) {
-                newBounds = options.getLaunchBounds();
-            }
-        }
-        return newBounds;
-    }
-
     void setLaunchSource(int uid) {
         mLaunchingActivity.setWorkSource(new WorkSource(uid));
     }
@@ -1518,7 +1526,7 @@
         //mWindowManager.dump();
 
         if (activityRemoved) {
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
 
         return r;
@@ -1611,35 +1619,17 @@
         }
     }
 
-    boolean resumeTopActivitiesLocked() {
-        return resumeTopActivitiesLocked(null, null, null);
+    boolean resumeFocusedStackTopActivityLocked() {
+        return resumeFocusedStackTopActivityLocked(null, null, null);
     }
 
-    boolean resumeTopActivitiesLocked(
+    boolean resumeFocusedStackTopActivityLocked(
             ActivityStack targetStack, ActivityRecord target, ActivityOptions targetOptions) {
-        if (targetStack == null) {
-            targetStack = mFocusedStack;
+        if (targetStack != null && isFocusedStack(targetStack)) {
+            return targetStack.resumeTopActivityUncheckedLocked(target, targetOptions);
         }
-        // Do targetStack first.
-        boolean result = false;
-        if (isFocusedStack(targetStack)) {
-            result = targetStack.resumeTopActivityLocked(target, targetOptions);
-        }
-
-        for (int displayNdx = mActivityDisplays.size() - 1; displayNdx >= 0; --displayNdx) {
-            final ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
-            for (int stackNdx = stacks.size() - 1; stackNdx >= 0; --stackNdx) {
-                final ActivityStack stack = stacks.get(stackNdx);
-                if (stack == targetStack) {
-                    // Already started above.
-                    continue;
-                }
-                if (isFocusedStack(stack)) {
-                    stack.resumeTopActivityLocked(null);
-                }
-            }
-        }
-        return result;
+        mFocusedStack.resumeTopActivityUncheckedLocked(null, null);
+        return false;
     }
 
     void finishTopRunningActivityLocked(ProcessRecord app, String reason) {
@@ -1681,10 +1671,13 @@
         }
 
         if (task.mResizeable && options != null) {
-            if (canUseActivityOptionsLaunchBounds(options)) {
+            int stackId = options.getLaunchStackId();
+            if (canUseActivityOptionsLaunchBounds(options, stackId)) {
                 Rect bounds = options.getLaunchBounds();
                 task.updateOverrideConfiguration(bounds);
-                final int stackId = task.getLaunchStackId();
+                if (stackId == INVALID_STACK_ID) {
+                    stackId = task.getLaunchStackId();
+                }
                 if (stackId != task.stack.mStackId) {
                     moveTaskToStackUncheckedLocked(task, stackId, ON_TOP, !FORCE_FOCUS, reason);
                     // moveTaskToStackUncheckedLocked() should already placed the task on top,
@@ -1706,10 +1699,14 @@
                 "findTaskToMoveToFront: moved to front of stack=" + task.stack);
     }
 
-    private boolean canUseActivityOptionsLaunchBounds(ActivityOptions options) {
+    boolean canUseActivityOptionsLaunchBounds(ActivityOptions options, int launchStackId) {
         // We use the launch bounds in the activity options is the device supports freeform
-        // window management.
-        return options.hasLaunchBounds() && mService.mSupportsFreeformWindowManagement;
+        // window management or is launching into the pinned stack.
+        if (!options.hasLaunchBounds()) {
+            return false;
+        }
+        return (mService.mSupportsPictureInPicture && launchStackId == PINNED_STACK_ID)
+                || mService.mSupportsFreeformWindowManagement;
     }
 
     ActivityStack getStack(int stackId) {
@@ -1806,16 +1803,20 @@
         }
     }
 
-    void resizeStackLocked(int stackId, Rect bounds, boolean preserveWindows,
-            boolean allowResizeInDockedMode) {
+    void resizeStackLocked(int stackId, Rect bounds, Rect tempTaskBounds, Rect tempTaskInsetBounds,
+            boolean preserveWindows, boolean allowResizeInDockedMode) {
+        if (stackId == DOCKED_STACK_ID) {
+            resizeDockedStackLocked(bounds, tempTaskBounds, tempTaskInsetBounds, null, null,
+                    preserveWindows);
+            return;
+        }
         final ActivityStack stack = getStack(stackId);
         if (stack == null) {
             Slog.w(TAG, "resizeStack: stackId " + stackId + " not found.");
             return;
         }
 
-        if (!allowResizeInDockedMode
-                && stackId != DOCKED_STACK_ID && getStack(DOCKED_STACK_ID) != null) {
+        if (!allowResizeInDockedMode && getStack(DOCKED_STACK_ID) != null) {
             // If the docked stack exist we don't allow resizes of stacks not caused by the docked
             // stack size changing so things don't get out of sync.
             return;
@@ -1824,96 +1825,139 @@
         Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeStack_" + stackId);
         mWindowManager.deferSurfaceLayout();
         try {
-
-            if (bounds != null && mWindowManager.isFullscreenBounds(stackId, bounds)) {
-                // The bounds passed in corresponds to the fullscreen bounds which we normally
-                // represent with null. Go ahead and set it to null so that all tasks configuration
-                // can have the right fullscreen state.
-                bounds = null;
-            }
-
-            ActivityRecord r = stack.topRunningActivityLocked();
-
-            mTmpBounds.clear();
-            mTmpConfigs.clear();
-            ArrayList<TaskRecord> tasks = stack.getAllTasks();
-            for (int i = tasks.size() - 1; i >= 0; i--) {
-                TaskRecord task = tasks.get(i);
-                if (task.mResizeable) {
-                    if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
-                        // For freeform stack we don't adjust the size of the tasks to match that
-                        // of the stack, but we do try to make sure the tasks are still contained
-                        // with the bounds of the stack.
-                        tempRect2.set(task.mBounds);
-                        fitWithinBounds(tempRect2, bounds);
-                        task.updateOverrideConfiguration(tempRect2);
-                    } else {
-                        task.updateOverrideConfiguration(bounds);
-                    }
-                }
-
-                mTmpConfigs.put(task.taskId, task.mOverrideConfig);
-                mTmpBounds.put(task.taskId, task.mBounds);
-            }
-            stack.mFullscreen = mWindowManager.resizeStack(stackId, bounds, mTmpConfigs, mTmpBounds);
-            if (stack.mStackId == DOCKED_STACK_ID) {
-                // Dock stack funness...Yay!
-                if (stack.mFullscreen) {
-                    // The dock stack went fullscreen which is kinda like dismissing it.
-                    // In this case we make all other static stacks fullscreen and move all
-                    // docked stack tasks to the fullscreen stack.
-                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                        if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
-                            resizeStackLocked(i, null, preserveWindows, true);
-                        }
-                    }
-
-                    final int count = tasks.size();
-                    for (int i = 0; i < count; i++) {
-                        moveTaskToStackLocked(tasks.get(i).taskId,
-                                FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
-                                false /* animate */);
-                    }
-
-                    // stack shouldn't contain anymore activities, so nothing to resume.
-                    r = null;
-                } else {
-                    // Docked stacks occupy a dedicated region on screen so the size of all other
-                    // static stacks need to be adjusted so they don't overlap with the docked stack.
-                    // We get the bounds to use from window manager which has been adjusted for any
-                    // screen controls and is also the same for all stacks.
-                    mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
-
-                    for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
-                        if (StackId.isResizeableByDockedStack(i)) {
-                            ActivityStack otherStack = getStack(i);
-                            if (otherStack != null) {
-                                resizeStackLocked(i, tempRect, PRESERVE_WINDOWS, true);
-                            }
-                        }
-                    }
-                }
-                // Since we are resizing the stack, all other operations should strive to preserve
-                // windows.
-                preserveWindows = true;
-            }
-            stack.setBounds(bounds);
-
-            if (r != null) {
-                final boolean updated = stack.ensureActivityConfigurationLocked(r, 0, preserveWindows);
-                // And we need to make sure at this point that all other activities
-                // are made visible with the correct configuration.
-                ensureActivitiesVisibleLocked(r, 0, preserveWindows);
-                if (!updated) {
-                    resumeTopActivitiesLocked(stack, null, null);
-                }
-            }
+            resizeStackUncheckedLocked(stack, bounds, tempTaskBounds, tempTaskInsetBounds);
+            ensureConfigurationAndResume(stack, stack.topRunningActivityLocked(), preserveWindows);
         } finally {
             mWindowManager.continueSurfaceLayout();
             Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
         }
     }
 
+    private void resizeStackUncheckedLocked(ActivityStack stack, Rect bounds, Rect tempTaskBounds,
+            Rect tempTaskInsetBounds) {
+        if (bounds != null && mWindowManager.isFullscreenBounds(stack.mStackId, bounds)) {
+            // The bounds passed in corresponds to the fullscreen bounds which we normally
+            // represent with null. Go ahead and set it to null so that all tasks configuration
+            // can have the right fullscreen state.
+            bounds = null;
+        }
+
+        mTmpBounds.clear();
+        mTmpConfigs.clear();
+        mTmpInsetBounds.clear();
+        ArrayList<TaskRecord> tasks = stack.getAllTasks();
+        for (int i = tasks.size() - 1; i >= 0; i--) {
+            TaskRecord task = tasks.get(i);
+            if (task.mResizeable) {
+                if (stack.mStackId == FREEFORM_WORKSPACE_STACK_ID) {
+                    // For freeform stack we don't adjust the size of the tasks to match that
+                    // of the stack, but we do try to make sure the tasks are still contained
+                    // with the bounds of the stack.
+                    tempRect2.set(task.mBounds);
+                    fitWithinBounds(tempRect2, bounds);
+                    task.updateOverrideConfiguration(tempRect2);
+                } else {
+                    task.updateOverrideConfiguration(tempTaskBounds != null
+                            ? tempTaskBounds : bounds);
+                }
+            }
+
+            mTmpConfigs.put(task.taskId, task.mOverrideConfig);
+            mTmpBounds.put(task.taskId, task.mBounds);
+            if (tempTaskInsetBounds != null) {
+                mTmpInsetBounds.put(task.taskId, tempTaskInsetBounds);
+            }
+        }
+
+        // We might trigger a configuration change. Save the current task bounds for freezing.
+        mWindowManager.prepareFreezingTaskBounds(stack.mStackId);
+        stack.mFullscreen = mWindowManager.resizeStack(stack.mStackId, bounds, mTmpConfigs,
+                mTmpBounds, mTmpInsetBounds);
+        stack.setBounds(bounds);
+    }
+
+    private void ensureConfigurationAndResume(ActivityStack stack, ActivityRecord r,
+            boolean preserveWindows) {
+        if (r == null) {
+            return;
+        }
+        final boolean updated = stack.ensureActivityConfigurationLocked(r, 0,
+                preserveWindows);
+        // And we need to make sure at this point that all other activities
+        // are made visible with the correct configuration.
+        ensureActivitiesVisibleLocked(r, 0, preserveWindows);
+        if (!updated) {
+            resumeFocusedStackTopActivityLocked();
+        }
+    }
+
+    void resizeDockedStackLocked(Rect dockedBounds, Rect tempDockedTaskBounds,
+            Rect tempDockedTaskInsetBounds,
+            Rect tempOtherTaskBounds, Rect tempOtherTaskInsetBounds, boolean preserveWindows) {
+        final ActivityStack stack = getStack(DOCKED_STACK_ID);
+        if (stack == null) {
+            Slog.w(TAG, "resizeDockedStackLocked: docked stack not found");
+            return;
+        }
+
+        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "am.resizeDockedStack");
+        mWindowManager.deferSurfaceLayout();
+        try {
+            ActivityRecord r = stack.topRunningActivityLocked();
+            resizeStackUncheckedLocked(stack, dockedBounds, tempDockedTaskBounds,
+                    tempDockedTaskInsetBounds);
+
+            if (stack.mFullscreen) {
+                // The dock stack went fullscreen which is kinda like dismissing it.
+                // In this case we make all other static stacks fullscreen and move all
+                // docked stack tasks to the fullscreen stack.
+                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                    if (StackId.isResizeableByDockedStack(i) && getStack(i) != null) {
+                        resizeStackLocked(i, null, null, null, preserveWindows,
+                                true /* allowResizeInDockedMode */);
+                    }
+                }
+
+                ArrayList<TaskRecord> tasks = stack.getAllTasks();
+                final int count = tasks.size();
+                for (int i = 0; i < count; i++) {
+                    moveTaskToStackLocked(tasks.get(i).taskId,
+                            FULLSCREEN_WORKSPACE_STACK_ID, ON_TOP, FORCE_FOCUS, "resizeStack",
+                            false /* animate */);
+                }
+
+                // stack shouldn't contain anymore activities, so nothing to resume.
+                r = null;
+            } else {
+                // Docked stacks occupy a dedicated region on screen so the size of all other
+                // static stacks need to be adjusted so they don't overlap with the docked stack.
+                // We get the bounds to use from window manager which has been adjusted for any
+                // screen controls and is also the same for all stacks.
+                mWindowManager.getStackDockedModeBounds(HOME_STACK_ID, tempRect);
+                for (int i = FIRST_STATIC_STACK_ID; i <= LAST_STATIC_STACK_ID; i++) {
+                    if (StackId.isResizeableByDockedStack(i)) {
+                        ActivityStack otherStack = getStack(i);
+                        if (otherStack != null) {
+                            resizeStackLocked(i, tempRect, tempOtherTaskBounds,
+                                    tempOtherTaskInsetBounds, preserveWindows,
+                                    true /* allowResizeInDockedMode */);
+                        }
+                    }
+                }
+            }
+            ensureConfigurationAndResume(stack, r, preserveWindows);
+        } finally {
+            mWindowManager.continueSurfaceLayout();
+            Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
+        }
+
+        mResizeDockedStackTimeout.notifyResizing(dockedBounds,
+                tempDockedTaskBounds != null
+                || tempDockedTaskInsetBounds != null
+                || tempOtherTaskBounds != null
+                || tempOtherTaskInsetBounds != null);
+    }
+
     void resizeTaskLocked(TaskRecord task, Rect bounds, int resizeMode, boolean preserveWindow) {
         if (!task.mResizeable) {
             Slog.w(TAG, "resizeTask: task " + task + " not resizeable.");
@@ -1961,7 +2005,7 @@
                 // All other activities must be made visible with their correct configuration.
                 ensureActivitiesVisibleLocked(r, 0, !PRESERVE_WINDOWS);
                 if (!kept) {
-                    resumeTopActivitiesLocked(stack, null, null);
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -2083,8 +2127,14 @@
     ActivityStack moveTaskToStackUncheckedLocked(
             TaskRecord task, int stackId, boolean toTop, boolean forceFocus, String reason) {
         final ActivityRecord r = task.getTopActivity();
-        final boolean wasFocused = isFocusedStack(task.stack) && (topRunningActivityLocked() == r);
-        final boolean wasResumed = wasFocused && (task.stack.mResumedActivity == r);
+        final ActivityStack prevStack = task.stack;
+        final boolean wasFocused = isFocusedStack(prevStack) && (topRunningActivityLocked() == r);
+        final boolean wasResumed = wasFocused && (prevStack.mResumedActivity == r);
+        // In some cases the focused stack isn't the front stack. E.g. pinned stack.
+        // Whenever we are moving the top activity from the front stack we want to make sure to move
+        // the stack to the front.
+        final boolean wasFront = isFrontStack(prevStack)
+                && (prevStack.topRunningActivityLocked() == r);
 
         final boolean resizeable = task.mResizeable;
         // Temporarily disable resizeablility of task we are moving. We don't want it to be resized
@@ -2097,9 +2147,9 @@
         stack.addTask(task, toTop, reason);
 
         // If the task had focus before (or we're requested to move focus),
-        // move focus to the new stack.
-        stack.setFocusAndResumeStateIfNeeded(
-                r, forceFocus || wasFocused, wasResumed, reason);
+        // move focus to the new stack by moving the stack to the front.
+        stack.moveToFrontAndResumeStateIfNeeded(
+                r, forceFocus || wasFocused || wasFront, wasResumed, reason);
 
         return stack;
     }
@@ -2149,7 +2199,7 @@
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
 
         if (!task.mResizeable && isStackDockedInEffect(stackId)) {
             showNonResizeableDockToast(taskId);
@@ -2170,7 +2220,7 @@
             return false;
         }
 
-        if (!mService.mForceResizableActivities && !r.info.supportsPip) {
+        if (!mService.mForceResizableActivities && !r.supportsPictureInPicture()) {
             Slog.w(TAG,
                     "moveTopStackActivityToPinnedStackLocked: Picture-In-Picture not supported for "
                             + " r=" + r);
@@ -2194,13 +2244,18 @@
         }
 
         if (bounds != null) {
-            resizeStackLocked(stackId, bounds, !PRESERVE_WINDOWS, true);
+            resizeStackLocked(stackId, bounds, null /* tempTaskBounds */,
+                    null /* tempTaskInsetBounds */, !PRESERVE_WINDOWS, true);
         }
 
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
+
+        if (stackId == PINNED_STACK_ID) {
+            mService.notifyActivityPinnedLocked();
+        }
     }
 
     void positionTaskInStackLocked(int taskId, int stackId, int position) {
@@ -2219,7 +2274,7 @@
         // The task might have already been running and its visibility needs to be synchronized with
         // the visibility of the stack / windows.
         stack.ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
-        resumeTopActivitiesLocked();
+        resumeFocusedStackTopActivityLocked();
     }
 
     ActivityRecord findTaskLocked(ActivityRecord r) {
@@ -2329,7 +2384,7 @@
                 final ActivityStack stack = stacks.get(stackNdx);
                 stack.awakeFromSleepingLocked();
                 if (isFocusedStack(stack)) {
-                    resumeTopActivitiesLocked();
+                    resumeFocusedStackTopActivityLocked();
                 }
             }
         }
@@ -3124,7 +3179,7 @@
                     if (DEBUG_LOCKTASK) Slog.w(TAG_LOCKTASK,
                             "setLockTaskModeLocked: Tasks remaining, can't unlock");
                     lockedTask.performClearTaskLocked();
-                    resumeTopActivitiesLocked();
+                    resumeFocusedStackTopActivityLocked();
                     return;
                 }
             }
@@ -3165,7 +3220,7 @@
 
         if (andResume) {
             findTaskToMoveToFrontLocked(task, 0, null, reason);
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3233,7 +3288,7 @@
             didSomething = true;
         }
         if (didSomething) {
-            resumeTopActivitiesLocked();
+            resumeFocusedStackTopActivityLocked();
         }
     }
 
@@ -3241,6 +3296,14 @@
         return mLockTaskModeState;
     }
 
+    void activityRelaunchedLocked(IBinder token) {
+        mWindowManager.notifyAppRelaunchingFinished(token);
+    }
+
+    void activityRelaunchingLocked(ActivityRecord r) {
+        mWindowManager.notifyAppRelaunching(r.appToken);
+    }
+
     void logStackState() {
         mActivityMetricsLogger.logWindowState();
     }
@@ -3280,7 +3343,7 @@
                 } break;
                 case RESUME_TOP_ACTIVITY_MSG: {
                     synchronized (mService) {
-                        resumeTopActivitiesLocked();
+                        resumeFocusedStackTopActivityLocked();
                     }
                 } break;
                 case SLEEP_TIMEOUT_MSG: {
@@ -3661,7 +3724,7 @@
 
             mSurface = surface;
             if (surface != null) {
-                mStack.resumeTopActivityLocked(null);
+                resumeFocusedStackTopActivityLocked();
             } else {
                 mContainerState = CONTAINER_STATE_NO_SURFACE;
                 ((VirtualActivityDisplay) mActivityDisplay).setSurface(null);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index b16e160..f712613 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -1,14 +1,47 @@
 package com.android.server.am;
 
+import static android.app.Activity.RESULT_CANCELED;
+import static android.app.ActivityManager.INTENT_SENDER_ACTIVITY;
+import static android.app.ActivityManager.START_CLASS_NOT_FOUND;
+import static android.app.ActivityManager.START_DELIVERED_TO_TOP;
+import static android.app.ActivityManager.START_FLAG_ONLY_IF_NEEDED;
+import static android.app.ActivityManager.START_RETURN_INTENT_TO_CALLER;
+import static android.app.ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
+import static android.app.ActivityManager.START_SUCCESS;
+import static android.app.ActivityManager.START_TASK_TO_FRONT;
+import static android.app.ActivityManager.StackId;
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
 import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
 import static android.app.ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID;
+import static android.app.ActivityManager.StackId.HOME_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
+import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
+import static android.app.PendingIntent.FLAG_CANCEL_CURRENT;
+import static android.app.PendingIntent.FLAG_IMMUTABLE;
+import static android.app.PendingIntent.FLAG_ONE_SHOT;
+import static android.content.Context.KEYGUARD_SERVICE;
+import static android.content.Intent.EXTRA_INTENT;
+import static android.content.Intent.EXTRA_PACKAGE_NAME;
+import static android.content.Intent.EXTRA_TASK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK;
 import static android.content.Intent.FLAG_ACTIVITY_CLEAR_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS;
 import static android.content.Intent.FLAG_ACTIVITY_LAUNCH_TO_SIDE;
 import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK;
+import static android.content.Intent.FLAG_ACTIVITY_NO_ANIMATION;
+import static android.content.Intent.FLAG_ACTIVITY_NO_USER_ACTION;
 import static android.content.Intent.FLAG_ACTIVITY_TASK_ON_HOME;
+import static android.content.Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP;
+import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT;
+import static android.content.Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED;
+import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP;
+import static android.content.pm.ActivityInfo.DOCUMENT_LAUNCH_ALWAYS;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_INSTANCE;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TASK;
+import static android.content.pm.ActivityInfo.LAUNCH_SINGLE_TOP;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_CONFIGURATION;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_FOCUS;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_PERMISSIONS_REVIEW;
@@ -42,7 +75,6 @@
 import android.app.PendingIntent;
 import android.app.ProfilerInfo;
 import android.content.ComponentName;
-import android.content.Context;
 import android.content.IIntentSender;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -67,7 +99,6 @@
 
 import com.android.internal.app.HeavyWeightSwitcherActivity;
 import com.android.internal.app.IVoiceInteractor;
-import com.android.internal.widget.LockPatternUtils;
 import com.android.server.am.ActivityStackSupervisor.PendingActivityLaunch;
 import com.android.server.wm.WindowManagerService;
 
@@ -79,7 +110,7 @@
  * This class collects all the logic for determining how an intent and flags should be turned into
  * an activity and associated task and stack.
  */
-public class ActivityStarter {
+class ActivityStarter {
     private static final String TAG = TAG_WITH_CLASS_NAME ? "ActivityStarter" : TAG_AM;
     private static final String TAG_RESULTS = TAG + POSTFIX_RESULTS;
     private static final String TAG_FOCUS = TAG + POSTFIX_FOCUS;
@@ -92,6 +123,79 @@
 
     final ArrayList<PendingActivityLaunch> mPendingActivityLaunches = new ArrayList<>();
 
+    // Share state variable among methods when starting an activity.
+    private ActivityRecord mStartActivity;
+    private Intent mIntent;
+    private int mCallingUid;
+    private ActivityOptions mOptions;
+
+    private boolean mLaunchSingleTop;
+    private boolean mLaunchSingleInstance;
+    private boolean mLaunchSingleTask;
+    private boolean mLaunchTaskBehind;
+    private int mLaunchFlags;
+
+    private Rect mLaunchBounds;
+
+    private ActivityRecord mNotTop;
+    private boolean mDoResume;
+    private int mStartFlags;
+    private ActivityRecord mSourceRecord;
+
+    private TaskRecord mInTask;
+    private boolean mAddingToTask;
+    private TaskRecord mReuseTask;
+
+    private ActivityInfo mNewTaskInfo;
+    private Intent mNewTaskIntent;
+    private ActivityStack mSourceStack;
+    private ActivityStack mTargetStack;
+    // TODO: Is the mMoveHome flag really needed?
+    private boolean mMovedHome;
+    private boolean mMovedToFront;
+    private boolean mNoAnimation;
+    private boolean mKeepCurTransition;
+
+    private IVoiceInteractionSession mVoiceSession;
+    private IVoiceInteractor mVoiceInteractor;
+
+    private void reset() {
+        mStartActivity = null;
+        mIntent = null;
+        mCallingUid = -1;
+        mOptions = null;
+
+        mLaunchSingleTop = false;
+        mLaunchSingleInstance = false;
+        mLaunchSingleTask = false;
+        mLaunchTaskBehind = false;
+        mLaunchFlags = 0;
+
+        mLaunchBounds = null;
+
+        mNotTop = null;
+        mDoResume = false;
+        mStartFlags = 0;
+        mSourceRecord = null;
+
+        mInTask = null;
+        mAddingToTask = false;
+        mReuseTask = null;
+
+        mNewTaskInfo = null;
+        mNewTaskIntent = null;
+        mSourceStack = null;
+
+        mTargetStack = null;
+        mMovedHome = false;
+        mMovedToFront = false;
+        mNoAnimation = false;
+        mKeepCurTransition = false;
+
+        mVoiceSession = null;
+        mVoiceInteractor = null;
+    }
+
     ActivityStarter(ActivityManagerService service, ActivityStackSupervisor supervisor) {
         mService = service;
         mSupervisor = supervisor;
@@ -234,11 +338,10 @@
 
         final ActivityStack resultStack = resultRecord == null ? null : resultRecord.task.stack;
 
-        if (err != ActivityManager.START_SUCCESS) {
+        if (err != START_SUCCESS) {
             if (resultRecord != null) {
-                resultStack.sendActivityResultLocked(-1,
-                        resultRecord, resultWho, requestCode,
-                        Activity.RESULT_CANCELED, null);
+                resultStack.sendActivityResultLocked(
+                        -1, resultRecord, resultWho, requestCode, RESULT_CANCELED, null);
             }
             ActivityOptions.abort(options);
             return err;
@@ -262,48 +365,36 @@
             }
         }
 
-        UserInfo user = mSupervisor.getUserInfo(userId);
-        KeyguardManager km = (KeyguardManager) mService.mContext
-                .getSystemService(Context.KEYGUARD_SERVICE);
-        if (user.isManagedProfile()
-                && LockPatternUtils.isSeparateWorkChallengeEnabled()
-                && km.isDeviceLocked(userId)) {
-            IIntentSender target = mService.getIntentSenderLocked(
-                    ActivityManager.INTENT_SENDER_ACTIVITY, callingPackage,
-                    Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
-                    new String[]{ resolvedType },
-                    PendingIntent.FLAG_CANCEL_CURRENT | PendingIntent.FLAG_ONE_SHOT
-                            | PendingIntent.FLAG_IMMUTABLE, null);
-            final int flags = intent.getFlags();
-            final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, user.id);
-            if (newIntent != null) {
-                intent = newIntent;
-                intent.setFlags(flags
-                        | Intent.FLAG_ACTIVITY_NEW_TASK
-                        | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
-                intent.putExtra(Intent.EXTRA_PACKAGE_NAME, aInfo.packageName);
-                intent.putExtra(Intent.EXTRA_INTENT, new IntentSender(target));
-
-                resolvedType = null;
-                callingUid = realCallingUid;
-                callingPid = realCallingPid;
-
-                UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
-                rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id);
-                aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
-                        null /*profilerInfo*/);
+        final Intent interceptingIntent = interceptWithConfirmCredentialsIfNeeded(intent,
+                resolvedType, aInfo, callingPackage, userId);
+        if (interceptingIntent != null) {
+            intent = interceptingIntent;
+            callingPid = realCallingPid;
+            callingUid = realCallingUid;
+            resolvedType = null;
+            // If we are intercepting and there was a task, convert it into an extra for the
+            // ConfirmCredentials intent and unassign it, as otherwise the task will move to
+            // front even if ConfirmCredentials is cancelled.
+            if (inTask != null) {
+                intent.putExtra(EXTRA_TASK_ID, inTask.taskId);
+                inTask = null;
             }
+
+            final UserInfo parent = UserManager.get(mService.mContext).getProfileParent(userId);
+            rInfo = mSupervisor.resolveIntent(intent, resolvedType, parent.id);
+            aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
+                    null /*profilerInfo*/);
         }
 
         if (abort) {
             if (resultRecord != null) {
                 resultStack.sendActivityResultLocked(-1, resultRecord, resultWho, requestCode,
-                        Activity.RESULT_CANCELED, null);
+                        RESULT_CANCELED, null);
             }
             // We pretend to the caller that it was really started, but
             // they will just get a cancel result.
             ActivityOptions.abort(options);
-            return ActivityManager.START_SUCCESS;
+            return START_SUCCESS;
         }
 
         // If permissions need a review before any of the app components can run, we
@@ -429,8 +520,8 @@
 
         doPendingActivityLaunchesLocked(false);
 
-        err = startActivityUncheckedLocked(r, sourceRecord, voiceSession,
-                voiceInteractor, startFlags, true, options, inTask);
+        err = startActivityUnchecked(
+                r, sourceRecord, voiceSession, voiceInteractor, startFlags, true, options, inTask);
 
         if (err < 0) {
             // If someone asked to have the keyguard dismissed on the next
@@ -442,6 +533,34 @@
         return err;
     }
 
+    /**
+     * Creates an intent to intercept the current activity start with Confirm Credentials if needed.
+     *
+     * @return The intercepting intent if needed.
+     */
+    private Intent interceptWithConfirmCredentialsIfNeeded(Intent intent, String resolvedType,
+            ActivityInfo aInfo, String callingPackage, int userId) {
+        if (!mService.mUserController.shouldConfirmCredentials(userId)) {
+            return null;
+        }
+        final IIntentSender target = mService.getIntentSenderLocked(
+                INTENT_SENDER_ACTIVITY, callingPackage,
+                Binder.getCallingUid(), userId, null, null, 0, new Intent[]{ intent },
+                new String[]{ resolvedType },
+                FLAG_CANCEL_CURRENT | FLAG_ONE_SHOT | FLAG_IMMUTABLE, null);
+        final int flags = intent.getFlags();
+        final KeyguardManager km = (KeyguardManager) mService.mContext
+                .getSystemService(KEYGUARD_SERVICE);
+        final Intent newIntent = km.createConfirmDeviceCredentialIntent(null, null, userId);
+        if (newIntent == null) {
+            return null;
+        }
+        newIntent.setFlags(flags | FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);
+        newIntent.putExtra(EXTRA_PACKAGE_NAME, aInfo.packageName);
+        newIntent.putExtra(EXTRA_INTENT, new IntentSender(target));
+        return newIntent;
+    }
+
     void startHomeActivityLocked(Intent intent, ActivityInfo aInfo, String reason) {
         mSupervisor.moveHomeStackTaskToTop(HOME_ACTIVITY_TYPE, reason);
         startActivityLocked(null /*caller*/, intent, null /*ephemeralIntent*/,
@@ -608,7 +727,7 @@
                         } catch (InterruptedException e) {
                         }
                     } while (!outResult.timeout && outResult.who == null);
-                } else if (res == ActivityManager.START_TASK_TO_FRONT) {
+                } else if (res == START_TASK_TO_FRONT) {
                     ActivityRecord r = stack.topRunningActivityLocked();
                     if (r.nowVisible && r.state == RESUMED) {
                         outResult.timeout = false;
@@ -632,682 +751,6 @@
         }
     }
 
-    final int startActivityUncheckedLocked(final ActivityRecord r, ActivityRecord sourceRecord,
-            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor, int startFlags,
-            boolean doResume, ActivityOptions options, TaskRecord inTask) {
-        final Intent intent = r.intent;
-        final int callingUid = r.launchedFromUid;
-
-        final Rect newBounds = mSupervisor.getOverrideBounds(r, options, inTask);
-        final boolean overrideBounds = newBounds != null;
-
-        // In some flows in to this function, we retrieve the task record and hold on to it
-        // without a lock before calling back in to here...  so the task at this point may
-        // not actually be in recents.  Check for that, and if it isn't in recents just
-        // consider it invalid.
-        if (inTask != null && !inTask.inRecents) {
-            Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
-            inTask = null;
-        }
-
-        final boolean launchSingleTop = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TOP;
-        final boolean launchSingleInstance = r.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE;
-        final boolean launchSingleTask = r.launchMode == ActivityInfo.LAUNCH_SINGLE_TASK;
-        int launchFlags = adjustLaunchFlagsToDocumentMode(r, launchSingleInstance, launchSingleTask,
-                intent.getFlags());
-        final boolean launchTaskBehind = r.mLaunchTaskBehind
-                && !launchSingleTask && !launchSingleInstance
-                && (launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
-
-        if (r.resultTo != null && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
-                && r.resultTo.task.stack != null) {
-            // For whatever reason this activity is being launched into a new
-            // task...  yet the caller has requested a result back.  Well, that
-            // is pretty messed up, so instead immediately send back a cancel
-            // and let the new task continue launched as normal without a
-            // dependency on its originator.
-            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
-            r.resultTo.task.stack.sendActivityResultLocked(-1,
-                    r.resultTo, r.resultWho, r.requestCode,
-                    Activity.RESULT_CANCELED, null);
-            r.resultTo = null;
-        }
-
-        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
-            launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-        }
-
-        // If we are actually going to launch in to a new task, there are some cases where
-        // we further want to do multiple task.
-        if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
-            if (launchTaskBehind
-                    || r.info.documentLaunchMode == ActivityInfo.DOCUMENT_LAUNCH_ALWAYS) {
-                launchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
-            }
-        }
-
-        // We'll invoke onUserLeaving before onPause only if the launching
-        // activity did not explicitly state that this is an automated launch.
-        mSupervisor.mUserLeaving = (launchFlags & Intent.FLAG_ACTIVITY_NO_USER_ACTION) == 0;
-        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
-                "startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
-
-        // If the caller has asked not to resume at this point, we make note
-        // of this in the record so that we can skip it when trying to find
-        // the top running activity.
-        if (!doResume || !mSupervisor.okToShowLocked(r)) {
-            r.delayedResume = true;
-            doResume = false;
-        }
-
-        final ActivityRecord notTop =
-                (launchFlags & Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
-
-        // If the onlyIfNeeded flag is set, then we can do this if the activity
-        // being launched is the same as the one making the call...  or, as
-        // a special case, if we do not know the caller then we count the
-        // current top activity as the caller.
-        if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-            ActivityRecord checkedCaller = sourceRecord;
-            if (checkedCaller == null) {
-                checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
-                        notTop);
-            }
-            if (!checkedCaller.realActivity.equals(r.realActivity)) {
-                // Caller is not the same as launcher, so always needed.
-                startFlags &= ~ActivityManager.START_FLAG_ONLY_IF_NEEDED;
-            }
-        }
-
-        boolean addingToTask = false;
-        TaskRecord reuseTask = null;
-
-        // If the caller is not coming from another activity, but has given us an
-        // explicit task into which they would like us to launch the new activity,
-        // then let's see about doing that.
-        if (sourceRecord == null && inTask != null && inTask.stack != null) {
-            final Intent baseIntent = inTask.getBaseIntent();
-            final ActivityRecord root = inTask.getRootActivity();
-            if (baseIntent == null) {
-                ActivityOptions.abort(options);
-                throw new IllegalArgumentException("Launching into task without base intent: "
-                        + inTask);
-            }
-
-            // If this task is empty, then we are adding the first activity -- it
-            // determines the root, and must be launching as a NEW_TASK.
-            if (launchSingleInstance || launchSingleTask) {
-                if (!baseIntent.getComponent().equals(r.intent.getComponent())) {
-                    ActivityOptions.abort(options);
-                    throw new IllegalArgumentException("Trying to launch singleInstance/Task "
-                            + r + " into different task " + inTask);
-                }
-                if (root != null) {
-                    ActivityOptions.abort(options);
-                    throw new IllegalArgumentException("Caller with inTask " + inTask
-                            + " has root " + root + " but target is singleInstance/Task");
-                }
-            }
-
-            // If task is empty, then adopt the interesting intent launch flags in to the
-            // activity being started.
-            if (root == null) {
-                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK
-                        | FLAG_ACTIVITY_MULTIPLE_TASK | Intent.FLAG_ACTIVITY_NEW_DOCUMENT
-                        | Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
-                launchFlags = (launchFlags&~flagsOfInterest)
-                        | (baseIntent.getFlags()&flagsOfInterest);
-                intent.setFlags(launchFlags);
-                inTask.setIntent(r);
-                addingToTask = true;
-
-                // If the task is not empty and the caller is asking to start it as the root
-                // of a new task, then we don't actually want to start this on the task.  We
-                // will bring the task to the front, and possibly give it a new intent.
-            } else if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
-                addingToTask = false;
-
-            } else {
-                addingToTask = true;
-            }
-
-            reuseTask = inTask;
-        } else {
-            inTask = null;
-            // Launch ResolverActivity in the source task, so that it stays in the task
-            // bounds when in freeform workspace.
-            // Also put noDisplay activities in the source task. These by itself can
-            // be placed in any task/stack, however it could launch other activities
-            // like ResolverActivity, and we want those to stay in the original task.
-            if ((r.isResolverActivity() || r.noDisplay) && sourceRecord != null
-                    && sourceRecord.isFreeform())  {
-                addingToTask = true;
-            }
-        }
-
-        if (inTask == null) {
-            if (sourceRecord == null) {
-                // This activity is not being started from another...  in this
-                // case we -always- start a new task.
-                if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && inTask == null) {
-                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
-                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
-                    launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-                }
-            } else if (sourceRecord.launchMode == ActivityInfo.LAUNCH_SINGLE_INSTANCE) {
-                // The original activity who is starting us is running as a single
-                // instance...  this new activity it is starting must go on its
-                // own task.
-                launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-            } else if (launchSingleInstance || launchSingleTask) {
-                // The activity being started is a single instance...  it always
-                // gets launched into its own task.
-                launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-            }
-        }
-
-        ActivityInfo newTaskInfo = null;
-        Intent newTaskIntent = null;
-        final ActivityStack sourceStack;
-        if (sourceRecord != null) {
-            if (sourceRecord.finishing) {
-                // If the source is finishing, we can't further count it as our source.  This
-                // is because the task it is associated with may now be empty and on its way out,
-                // so we don't want to blindly throw it in to that task.  Instead we will take
-                // the NEW_TASK flow and try to find a task for it. But save the task information
-                // so it can be used when creating the new task.
-                if ((launchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
-                    Slog.w(TAG, "startActivity called from finishing " + sourceRecord
-                            + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + intent);
-                    launchFlags |= FLAG_ACTIVITY_NEW_TASK;
-                    newTaskInfo = sourceRecord.info;
-                    newTaskIntent = sourceRecord.task.intent;
-                }
-                sourceRecord = null;
-                sourceStack = null;
-            } else {
-                sourceStack = sourceRecord.task.stack;
-            }
-        } else {
-            sourceStack = null;
-        }
-
-        boolean movedHome = false;
-        ActivityStack targetStack;
-
-        intent.setFlags(launchFlags);
-        final boolean noAnimation = (launchFlags & Intent.FLAG_ACTIVITY_NO_ANIMATION) != 0;
-
-        ActivityRecord intentActivity = getReusableIntentActivity(r, inTask, intent,
-                launchSingleInstance, launchSingleTask, launchFlags);
-        if (intentActivity != null) {
-            // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused
-            // but still needs to be a lock task mode violation since the task gets
-            // cleared out and the device would otherwise leave the locked task.
-            if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
-                    (launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
-                mSupervisor.showLockTaskToast();
-                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            if (r.task == null) {
-                r.task = intentActivity.task;
-            }
-            if (intentActivity.task.intent == null) {
-                // This task was started because of movement of the activity based on affinity...
-                // Now that we are actually launching it, we can assign the base intent.
-                intentActivity.task.setIntent(r);
-            }
-
-            targetStack = intentActivity.task.stack;
-            targetStack.mLastPausedActivity = null;
-            // If the target task is not in the front, then we need
-            // to bring it to the front...  except...  well, with
-            // SINGLE_TASK_LAUNCH it's not entirely clear.  We'd like
-            // to have the same behavior as if a new instance was
-            // being started, which means not bringing it to the front
-            // if the caller is not itself in the front.
-            final ActivityStack focusStack = mSupervisor.getFocusedStack();
-            ActivityRecord curTop = (focusStack == null)
-                    ? null : focusStack.topRunningNonDelayedActivityLocked(notTop);
-            boolean movedToFront = false;
-            if (curTop != null && (curTop.task != intentActivity.task ||
-                    curTop.task != focusStack.topTask())) {
-                r.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
-                if (sourceRecord == null || (sourceStack.topActivity() != null &&
-                        sourceStack.topActivity().task == sourceRecord.task)) {
-                    // We really do want to push this one into the user's face, right now.
-                    if (launchTaskBehind && sourceRecord != null) {
-                        intentActivity.setTaskToAffiliateWith(sourceRecord.task);
-                    }
-                    movedHome = true;
-                    final ActivityStack sideStack = getLaunchToSideStack(r, launchFlags, r.task);
-                    if (sideStack == null || sideStack == targetStack) {
-                        // We only want to move to the front, if we aren't going to launch on a
-                        // different stack. If we launch on a different stack, we will put the
-                        // task on top there.
-                        targetStack.moveTaskToFrontLocked(intentActivity.task, noAnimation,
-                                options, r.appTimeTracker, "bringingFoundTaskToFront");
-                        movedToFront = true;
-                    }
-                    if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                        // Caller wants to appear on home activity.
-                        intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-                    }
-                    options = null;
-                }
-            }
-            if (!movedToFront && doResume) {
-                if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + targetStack
-                        + " from " + intentActivity);
-                targetStack.moveToFront("intentActivityFound");
-            }
-
-            // If the caller has requested that the target task be
-            // reset, then do so.
-            if ((launchFlags & Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
-                intentActivity = targetStack.resetTaskIfNeededLocked(intentActivity, r);
-            }
-            if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                // We don't need to start a new activity, and
-                // the client said not to do anything if that
-                // is the case, so this is it!  And for paranoia, make
-                // sure we have correctly resumed the top activity.
-                if (doResume) {
-                    mSupervisor.resumeTopActivitiesLocked(targetStack, null, options);
-
-                    // Make sure to notify Keyguard as well if we are not running an app
-                    // transition later.
-                    if (!movedToFront) {
-                        mSupervisor.notifyActivityDrawnForKeyguard();
-                    }
-                } else {
-                    ActivityOptions.abort(options);
-                }
-                mSupervisor.updateUserStackLocked(r.userId, targetStack);
-                return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-            }
-            if ((launchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
-                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
-                // The caller has requested to completely replace any
-                // existing task with its new activity.  Well that should
-                // not be too hard...
-                reuseTask = intentActivity.task;
-                reuseTask.performClearTaskLocked();
-                reuseTask.setIntent(r);
-            } else if ((launchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
-                    || launchSingleInstance || launchSingleTask) {
-                // In this situation we want to remove all activities
-                // from the task up to the one being started.  In most
-                // cases this means we are resetting the task to its
-                // initial state.
-                ActivityRecord top = intentActivity.task.performClearTaskLocked(r, launchFlags);
-                if (top != null) {
-                    if (top.frontOfTask) {
-                        // Activity aliases may mean we use different
-                        // intents for the top activity, so make sure
-                        // the task now has the identity of the new
-                        // intent.
-                        top.task.setIntent(r);
-                    }
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                } else {
-                    // A special case: we need to start the activity because it is not
-                    // currently running, and the caller has asked to clear the current
-                    // task to have this activity at the top.
-                    addingToTask = true;
-                    // Now pretend like this activity is being started by the top of its
-                    // task, so it is put in the right place.
-                    sourceRecord = intentActivity;
-                    TaskRecord task = sourceRecord.task;
-                    if (task != null && task.stack == null) {
-                        // Target stack got cleared when we all activities were removed
-                        // above. Go ahead and reset it.
-                        targetStack = computeStackFocus(
-                                sourceRecord, false /* newTask */, null /* bounds */, launchFlags);
-                        targetStack.addTask(task,
-                                !launchTaskBehind /* toTop */, "startActivityUnchecked");
-                    }
-
-                }
-            } else if (r.realActivity.equals(intentActivity.task.realActivity)) {
-                // In this case the top activity on the task is the
-                // same as the one being launched, so we take that
-                // as a request to bring the task to the foreground.
-                // If the top activity in the task is the root
-                // activity, deliver this new intent to it if it
-                // desires.
-                if (((launchFlags&Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0 || launchSingleTop)
-                        && intentActivity.realActivity.equals(r.realActivity)) {
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r,
-                            intentActivity.task);
-                    if (intentActivity.frontOfTask) {
-                        intentActivity.task.setIntent(r);
-                    }
-                    intentActivity.deliverNewIntentLocked(callingUid, r.intent,
-                            r.launchedFromPackage);
-                } else if (!r.intent.filterEquals(intentActivity.task.intent)) {
-                    // In this case we are launching the root activity
-                    // of the task, but with a different intent.  We
-                    // should start a new instance on top.
-                    addingToTask = true;
-                    sourceRecord = intentActivity;
-                }
-            } else if ((launchFlags&Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
-                // In this case an activity is being launched in to an
-                // existing task, without resetting that task.  This
-                // is typically the situation of launching an activity
-                // from a notification or shortcut.  We want to place
-                // the new activity on top of the current task.
-                addingToTask = true;
-                sourceRecord = intentActivity;
-            } else if (!intentActivity.task.rootWasReset) {
-                // In this case we are launching in to an existing task
-                // that has not yet been started from its front door.
-                // The current task has been brought to the front.
-                // Ideally, we'd probably like to place this new task
-                // at the bottom of its stack, but that's a little hard
-                // to do with the current organization of the code so
-                // for now we'll just drop it.
-                intentActivity.task.setIntent(r);
-            }
-            if (!addingToTask && reuseTask == null) {
-                // We didn't do anything...  but it was needed (a.k.a., client
-                // don't use that intent!)  And for paranoia, make
-                // sure we have correctly resumed the top activity.
-                if (doResume) {
-                    targetStack.resumeTopActivityLocked(null, options);
-                    if (!movedToFront) {
-                        // Make sure to notify Keyguard as well if we are not running an app
-                        // transition later.
-                        mSupervisor.notifyActivityDrawnForKeyguard();
-                    }
-                } else {
-                    ActivityOptions.abort(options);
-                }
-                mSupervisor.updateUserStackLocked(r.userId, targetStack);
-                return ActivityManager.START_TASK_TO_FRONT;
-            }
-        }
-
-        //String uri = r.intent.toURI();
-        //Intent intent2 = new Intent(uri);
-        //Slog.i(TAG, "Given intent: " + r.intent);
-        //Slog.i(TAG, "URI is: " + uri);
-        //Slog.i(TAG, "To intent: " + intent2);
-
-        if (r.packageName != null) {
-            // If the activity being launched is the same as the one currently
-            // at the top, then we need to check if it should only be launched
-            // once.
-            ActivityStack topStack = mSupervisor.mFocusedStack;
-            ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(notTop);
-            final boolean dontStart = top != null && r.resultTo == null
-                    && top.realActivity.equals(r.realActivity) && top.userId == r.userId
-                    && top.app != null && top.app.thread != null
-                    && ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
-                    || launchSingleTop || launchSingleTask);
-            if (dontStart) {
-                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
-                // For paranoia, make sure we have correctly resumed the top activity.
-                topStack.mLastPausedActivity = null;
-                if (doResume) {
-                    mSupervisor.resumeTopActivitiesLocked();
-                }
-                ActivityOptions.abort(options);
-                if ((startFlags & ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                    // We don't need to start a new activity, and the client said not to do
-                    // anything if that is the case, so this is it!
-                    return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                }
-                top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                return ActivityManager.START_DELIVERED_TO_TOP;
-            }
-        } else {
-            if (r.resultTo != null && r.resultTo.task.stack != null) {
-                r.resultTo.task.stack.sendActivityResultLocked(-1, r.resultTo, r.resultWho,
-                        r.requestCode, Activity.RESULT_CANCELED, null);
-            }
-            ActivityOptions.abort(options);
-            return ActivityManager.START_CLASS_NOT_FOUND;
-        }
-
-        boolean newTask = false;
-        boolean keepCurTransition = false;
-
-        final TaskRecord taskToAffiliate = launchTaskBehind && sourceRecord != null ?
-                sourceRecord.task : null;
-
-        // Should this be considered a new task?
-        if (r.resultTo == null && inTask == null && !addingToTask
-                && (launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
-            newTask = true;
-            targetStack = computeStackFocus(r, newTask, newBounds, launchFlags);
-            if (doResume) {
-                targetStack.moveToFront("startingNewTask");
-            }
-
-            if (reuseTask == null) {
-                r.setTask(targetStack.createTaskRecord(mSupervisor.getNextTaskId(),
-                        newTaskInfo != null ? newTaskInfo : r.info,
-                        newTaskIntent != null ? newTaskIntent : intent,
-                        voiceSession, voiceInteractor, !launchTaskBehind /* toTop */),
-                        taskToAffiliate);
-                if (overrideBounds) {
-                    r.task.updateOverrideConfiguration(newBounds);
-                }
-                if (DEBUG_TASKS) Slog.v(TAG_TASKS,
-                        "Starting new activity " + r + " in new task " + r.task);
-            } else {
-                r.setTask(reuseTask, taskToAffiliate);
-            }
-            if (mSupervisor.isLockTaskModeViolation(r.task)) {
-                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            if (!movedHome) {
-                if ((launchFlags &
-                        (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
-                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
-                    // Caller wants to appear on home activity, so before starting
-                    // their own activity we will bring home to the front.
-                    r.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
-                }
-            }
-        } else if (sourceRecord != null) {
-            final TaskRecord sourceTask = sourceRecord.task;
-            if (mSupervisor.isLockTaskModeViolation(sourceTask)) {
-                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            targetStack = null;
-            if (sourceTask.stack.topTask() != sourceTask) {
-                // We only want to allow changing stack if the target task is not the top one,
-                // otherwise we would move the launching task to the other side, rather than show
-                // two side by side.
-                targetStack = getLaunchToSideStack(r, launchFlags, r.task);
-            }
-            if (targetStack == null) {
-                targetStack = sourceTask.stack;
-            } else if (targetStack != sourceTask.stack) {
-                mSupervisor.moveTaskToStackLocked(sourceTask.taskId, targetStack.mStackId,
-                        ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
-            }
-            if (doResume) {
-                targetStack.moveToFront("sourceStackToFront");
-            }
-            final TaskRecord topTask = targetStack.topTask();
-            if (topTask != sourceTask) {
-                targetStack.moveTaskToFrontLocked(sourceTask, noAnimation, options,
-                        r.appTimeTracker, "sourceTaskToFront");
-            }
-            if (!addingToTask && (launchFlags&Intent.FLAG_ACTIVITY_CLEAR_TOP) != 0) {
-                // In this case, we are adding the activity to an existing
-                // task, but the caller has asked to clear that task if the
-                // activity is already running.
-                ActivityRecord top = sourceTask.performClearTaskLocked(r, launchFlags);
-                keepCurTransition = true;
-                if (top != null) {
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, top.task);
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                    // For paranoia, make sure we have correctly
-                    // resumed the top activity.
-                    targetStack.mLastPausedActivity = null;
-                    if (doResume) {
-                        targetStack.resumeTopActivityLocked(null);
-                    }
-                    ActivityOptions.abort(options);
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            } else if (!addingToTask &&
-                    (launchFlags&Intent.FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
-                // In this case, we are launching an activity in our own task
-                // that may already be running somewhere in the history, and
-                // we want to shuffle it to the front of the stack if so.
-                final ActivityRecord top = sourceTask.findActivityInHistoryLocked(r);
-                if (top != null) {
-                    final TaskRecord task = top.task;
-                    task.moveActivityToFrontLocked(top);
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, r, task);
-                    top.updateOptionsLocked(options);
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                    targetStack.mLastPausedActivity = null;
-                    if (doResume) {
-                        targetStack.resumeTopActivityLocked(null);
-                    }
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            }
-            // An existing activity is starting this new activity, so we want
-            // to keep the new one in the same task as the one that is starting
-            // it.
-            r.setTask(sourceTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
-                    + " in existing task " + r.task + " from source " + sourceRecord);
-
-        } else if (inTask != null) {
-            // The caller is asking that the new activity be started in an explicit
-            // task it has provided to us.
-            if (mSupervisor.isLockTaskModeViolation(inTask)) {
-                Slog.e(TAG, "Attempted Lock Task Mode violation r=" + r);
-                return ActivityManager.START_RETURN_LOCK_TASK_MODE_VIOLATION;
-            }
-            if (overrideBounds) {
-                inTask.updateOverrideConfiguration(newBounds);
-                int stackId = inTask.getLaunchStackId();
-                if (stackId != inTask.stack.mStackId) {
-                    mSupervisor.moveTaskToStackUncheckedLocked(
-                            inTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
-                }
-            }
-            targetStack = inTask.stack;
-            targetStack.moveTaskToFrontLocked(inTask, noAnimation, options, r.appTimeTracker,
-                    "inTaskToFront");
-
-            // Check whether we should actually launch the new activity in to the task,
-            // or just reuse the current activity on top.
-            ActivityRecord top = inTask.getTopActivity();
-            if (top != null && top.realActivity.equals(r.realActivity) && top.userId == r.userId) {
-                if ((launchFlags & Intent.FLAG_ACTIVITY_SINGLE_TOP) != 0
-                        || launchSingleTop || launchSingleTask) {
-                    ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
-                    if ((startFlags&ActivityManager.START_FLAG_ONLY_IF_NEEDED) != 0) {
-                        // We don't need to start a new activity, and
-                        // the client said not to do anything if that
-                        // is the case, so this is it!
-                        return ActivityManager.START_RETURN_INTENT_TO_CALLER;
-                    }
-                    top.deliverNewIntentLocked(callingUid, r.intent, r.launchedFromPackage);
-                    return ActivityManager.START_DELIVERED_TO_TOP;
-                }
-            }
-
-            if (!addingToTask) {
-                // We don't actually want to have this activity added to the task, so just
-                // stop here but still tell the caller that we consumed the intent.
-                ActivityOptions.abort(options);
-                return ActivityManager.START_TASK_TO_FRONT;
-            }
-
-            r.setTask(inTask, null);
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
-                    + " in explicit task " + r.task);
-
-        } else {
-            // This not being started from an existing activity, and not part
-            // of a new task...  just put it in the top task, though these days
-            // this case should never happen.
-            targetStack = computeStackFocus(r, newTask, null /* bounds */, launchFlags);
-            if (doResume) {
-                targetStack.moveToFront("addingToTopTask");
-            }
-            ActivityRecord prev = targetStack.topActivity();
-            r.setTask(prev != null ? prev.task : targetStack.createTaskRecord(
-                    mSupervisor.getNextTaskId(), r.info, intent, null, null, true), null);
-            mWindowManager.moveTaskToTop(r.task.taskId);
-            if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + r
-                    + " in new guessed " + r.task);
-        }
-
-        mService.grantUriPermissionFromIntentLocked(callingUid, r.packageName,
-                intent, r.getUriPermissionsLocked(), r.userId);
-
-        if (sourceRecord != null && sourceRecord.isRecentsActivity()) {
-            r.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
-        }
-        if (newTask) {
-            EventLog.writeEvent(EventLogTags.AM_CREATE_TASK, r.userId, r.task.taskId);
-        }
-        ActivityStack.logStartActivity(EventLogTags.AM_CREATE_ACTIVITY, r, r.task);
-        targetStack.mLastPausedActivity = null;
-        targetStack.startActivityLocked(r, newTask, keepCurTransition, options);
-        if (doResume) {
-            if (!launchTaskBehind) {
-                mService.setFocusedActivityLocked(r, "startedActivity");
-            }
-            mSupervisor.resumeTopActivitiesLocked(targetStack, r, options);
-        } else {
-            targetStack.addRecentActivityLocked(r);
-        }
-        mSupervisor.updateUserStackLocked(r.userId, targetStack);
-
-        if (!r.task.mResizeable && mSupervisor.isStackDockedInEffect(targetStack.mStackId)) {
-            mSupervisor.showNonResizeableDockToast(r.task.taskId);
-        }
-
-        return ActivityManager.START_SUCCESS;
-    }
-
-    private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
-            boolean launchSingleTask, int launchFlags) {
-        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
-                (launchSingleInstance || launchSingleTask)) {
-            // We have a conflict between the Intent and the Activity manifest, manifest wins.
-            Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
-                    "\"singleInstance\" or \"singleTask\"");
-            launchFlags &=
-                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
-        } else {
-            switch (r.info.documentLaunchMode) {
-                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
-                    break;
-                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
-                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-                    break;
-                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
-                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
-                    break;
-                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
-                    launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
-                    break;
-            }
-        }
-        return launchFlags;
-    }
-
     final int startActivities(IApplicationThread caller, int callingUid, String callingPackage,
             Intent[] intents, String[] resolvedTypes, IBinder resultTo,
             Bundle bOptions, int userId) {
@@ -1381,7 +824,743 @@
             Binder.restoreCallingIdentity(origId);
         }
 
-        return ActivityManager.START_SUCCESS;
+        return START_SUCCESS;
+    }
+
+    private int startActivityUnchecked(final ActivityRecord r, ActivityRecord sourceRecord,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor,
+            int startFlags, boolean doResume, ActivityOptions options, TaskRecord inTask) {
+
+        setInitialState(r, options, inTask, doResume, startFlags, sourceRecord, voiceSession,
+                voiceInteractor);
+
+        computeLaunchingTaskFlags();
+
+        computeSourceStack();
+
+        mIntent.setFlags(mLaunchFlags);
+
+        ActivityRecord intentActivity = getReusableIntentActivity();
+
+        if (intentActivity != null) {
+            // When the flags NEW_TASK and CLEAR_TASK are set, then the task gets reused but
+            // still needs to be a lock task mode violation since the task gets cleared out and
+            // the device would otherwise leave the locked task.
+            if (mSupervisor.isLockTaskModeViolation(intentActivity.task,
+                    (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                            == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))) {
+                mSupervisor.showLockTaskToast();
+                Slog.e(TAG, "startActivityUnchecked: Attempt to violate Lock Task Mode");
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+
+            if (mStartActivity.task == null) {
+                mStartActivity.task = intentActivity.task;
+            }
+            if (intentActivity.task.intent == null) {
+                // This task was started because of movement of the activity based on affinity...
+                // Now that we are actually launching it, we can assign the base intent.
+                intentActivity.task.setIntent(mStartActivity);
+            }
+
+            intentActivity = setTargetStackAndMoveToFrontIfNeeded(intentActivity);
+
+            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+                // We don't need to start a new activity, and the client said not to do anything
+                // if that is the case, so this is it!  And for paranoia, make sure we have
+                // correctly resumed the top activity.
+                resumeTargetStackIfNeeded();
+                return START_RETURN_INTENT_TO_CALLER;
+            }
+
+            setTaskFromIntentActivity(intentActivity);
+
+            if (!mAddingToTask && mReuseTask == null) {
+                // We didn't do anything...  but it was needed (a.k.a., client don't use that
+                // intent!)  And for paranoia, make sure we have correctly resumed the top activity.
+                resumeTargetStackIfNeeded();
+                return START_TASK_TO_FRONT;
+            }
+        }
+
+        if (mStartActivity.packageName == null) {
+            if (mStartActivity.resultTo != null && mStartActivity.resultTo.task.stack != null) {
+                mStartActivity.resultTo.task.stack.sendActivityResultLocked(
+                        -1, mStartActivity.resultTo, mStartActivity.resultWho,
+                        mStartActivity.requestCode, RESULT_CANCELED, null);
+            }
+            ActivityOptions.abort(mOptions);
+            return START_CLASS_NOT_FOUND;
+        }
+
+        // If the activity being launched is the same as the one currently at the top, then
+        // we need to check if it should only be launched once.
+        final ActivityStack topStack = mSupervisor.mFocusedStack;
+        final ActivityRecord top = topStack.topRunningNonDelayedActivityLocked(mNotTop);
+        final boolean dontStart = top != null && mStartActivity.resultTo == null
+                && top.realActivity.equals(mStartActivity.realActivity)
+                && top.userId == mStartActivity.userId
+                && top.app != null && top.app.thread != null
+                && ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+                || mLaunchSingleTop || mLaunchSingleTask);
+        if (dontStart) {
+            ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
+            // For paranoia, make sure we have correctly resumed the top activity.
+            topStack.mLastPausedActivity = null;
+            if (mDoResume) {
+                mSupervisor.resumeFocusedStackTopActivityLocked();
+            }
+            ActivityOptions.abort(mOptions);
+            if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+                // We don't need to start a new activity, and the client said not to do
+                // anything if that is the case, so this is it!
+                return START_RETURN_INTENT_TO_CALLER;
+            }
+            top.deliverNewIntentLocked(
+                    mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+            return START_DELIVERED_TO_TOP;
+        }
+
+        boolean newTask = false;
+        final TaskRecord taskToAffiliate = (mLaunchTaskBehind && mSourceRecord != null)
+                ? mSourceRecord.task : null;
+
+        // Should this be considered a new task?
+        if (mStartActivity.resultTo == null && mInTask == null && !mAddingToTask
+                && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+            newTask = true;
+            setTaskFromReuseOrCreateNewTask(taskToAffiliate);
+
+            if (mSupervisor.isLockTaskModeViolation(mStartActivity.task)) {
+                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+            if (!mMovedHome
+                    && (mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                    == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+                // Caller wants to appear on home activity, so before starting
+                // their own activity we will bring home to the front.
+                mStartActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+            }
+        } else if (mSourceRecord != null) {
+            if (mSupervisor.isLockTaskModeViolation(mSourceRecord.task)) {
+                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+
+            final int result = setTaskFromSourceRecord();
+            if (result != START_SUCCESS) {
+                return result;
+            }
+        } else if (mInTask != null) {
+            // The caller is asking that the new activity be started in an explicit
+            // task it has provided to us.
+            if (mSupervisor.isLockTaskModeViolation(mInTask)) {
+                Slog.e(TAG, "Attempted Lock Task Mode violation mStartActivity=" + mStartActivity);
+                return START_RETURN_LOCK_TASK_MODE_VIOLATION;
+            }
+
+            final int result = setTaskFromInTask();
+            if (result != START_SUCCESS) {
+                return result;
+            }
+        } else {
+            // This not being started from an existing activity, and not part of a new task...
+            // just put it in the top task, though these days this case should never happen.
+            setTaskToCurrentTopOrCreateNewTask();
+        }
+
+        mService.grantUriPermissionFromIntentLocked(mCallingUid, mStartActivity.packageName,
+                mIntent, mStartActivity.getUriPermissionsLocked(), mStartActivity.userId);
+
+        if (mSourceRecord != null && mSourceRecord.isRecentsActivity()) {
+            mStartActivity.task.setTaskToReturnTo(RECENTS_ACTIVITY_TYPE);
+        }
+        if (newTask) {
+            EventLog.writeEvent(
+                    EventLogTags.AM_CREATE_TASK, mStartActivity.userId, mStartActivity.task.taskId);
+        }
+        ActivityStack.logStartActivity(
+                EventLogTags.AM_CREATE_ACTIVITY, mStartActivity, mStartActivity.task);
+        mTargetStack.mLastPausedActivity = null;
+        mTargetStack.startActivityLocked(mStartActivity, newTask, mKeepCurTransition, mOptions);
+        if (mDoResume) {
+            if (!mLaunchTaskBehind) {
+                // TODO(b/26381750): Remove this code after verification that all the decision
+                // points above moved targetStack to the front which will also set the focus
+                // activity.
+                mService.setFocusedActivityLocked(mStartActivity, "startedActivity");
+            }
+            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, mStartActivity,
+                    mOptions);
+        } else {
+            mTargetStack.addRecentActivityLocked(mStartActivity);
+        }
+        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+
+        if (!mStartActivity.task.mResizeable
+                && mSupervisor.isStackDockedInEffect(mTargetStack.mStackId)) {
+            mSupervisor.showNonResizeableDockToast(mStartActivity.task.taskId);
+        }
+
+        return START_SUCCESS;
+    }
+
+    private void setInitialState(ActivityRecord r, ActivityOptions options, TaskRecord inTask,
+            boolean doResume, int startFlags, ActivityRecord sourceRecord,
+            IVoiceInteractionSession voiceSession, IVoiceInteractor voiceInteractor) {
+        reset();
+
+        mStartActivity = r;
+        mIntent = r.intent;
+        mOptions = options;
+        mCallingUid = r.launchedFromUid;
+        mSourceRecord = sourceRecord;
+        mVoiceSession = voiceSession;
+        mVoiceInteractor = voiceInteractor;
+
+        mLaunchBounds = getOverrideBounds(r, options, inTask);
+
+        mLaunchSingleTop = r.launchMode == LAUNCH_SINGLE_TOP;
+        mLaunchSingleInstance = r.launchMode == LAUNCH_SINGLE_INSTANCE;
+        mLaunchSingleTask = r.launchMode == LAUNCH_SINGLE_TASK;
+        mLaunchFlags = adjustLaunchFlagsToDocumentMode(
+                r, mLaunchSingleInstance, mLaunchSingleTask, mIntent.getFlags());
+        mLaunchTaskBehind = r.mLaunchTaskBehind
+                && !mLaunchSingleTask && !mLaunchSingleInstance
+                && (mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0;
+
+        sendNewTaskResultRequestIfNeeded();
+
+        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_DOCUMENT) != 0 && r.resultTo == null) {
+            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+        }
+
+        // If we are actually going to launch in to a new task, there are some cases where
+        // we further want to do multiple task.
+        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+            if (mLaunchTaskBehind
+                    || r.info.documentLaunchMode == DOCUMENT_LAUNCH_ALWAYS) {
+                mLaunchFlags |= FLAG_ACTIVITY_MULTIPLE_TASK;
+            }
+        }
+
+        // We'll invoke onUserLeaving before onPause only if the launching
+        // activity did not explicitly state that this is an automated launch.
+        mSupervisor.mUserLeaving = (mLaunchFlags & FLAG_ACTIVITY_NO_USER_ACTION) == 0;
+        if (DEBUG_USER_LEAVING) Slog.v(TAG_USER_LEAVING,
+                "startActivity() => mUserLeaving=" + mSupervisor.mUserLeaving);
+
+        // If the caller has asked not to resume at this point, we make note
+        // of this in the record so that we can skip it when trying to find
+        // the top running activity.
+        mDoResume = doResume;
+        if (!doResume || !mSupervisor.okToShowLocked(r)) {
+            r.delayedResume = true;
+            mDoResume = false;
+        }
+
+        mNotTop = (mLaunchFlags & FLAG_ACTIVITY_PREVIOUS_IS_TOP) != 0 ? r : null;
+
+        mInTask = inTask;
+        // In some flows in to this function, we retrieve the task record and hold on to it
+        // without a lock before calling back in to here...  so the task at this point may
+        // not actually be in recents.  Check for that, and if it isn't in recents just
+        // consider it invalid.
+        if (inTask != null && !inTask.inRecents) {
+            Slog.w(TAG, "Starting activity in task not in recents: " + inTask);
+            mInTask = null;
+        }
+
+        mStartFlags = startFlags;
+        // If the onlyIfNeeded flag is set, then we can do this if the activity being launched
+        // is the same as the one making the call...  or, as a special case, if we do not know
+        // the caller then we count the current top activity as the caller.
+        if ((startFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+            ActivityRecord checkedCaller = sourceRecord;
+            if (checkedCaller == null) {
+                checkedCaller = mSupervisor.mFocusedStack.topRunningNonDelayedActivityLocked(
+                        mNotTop);
+            }
+            if (!checkedCaller.realActivity.equals(r.realActivity)) {
+                // Caller is not the same as launcher, so always needed.
+                mStartFlags &= ~START_FLAG_ONLY_IF_NEEDED;
+            }
+        }
+
+        mNoAnimation = (mLaunchFlags & FLAG_ACTIVITY_NO_ANIMATION) != 0;
+    }
+
+    private void sendNewTaskResultRequestIfNeeded() {
+        if (mStartActivity.resultTo != null && (mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0
+                && mStartActivity.resultTo.task.stack != null) {
+            // For whatever reason this activity is being launched into a new task...
+            // yet the caller has requested a result back.  Well, that is pretty messed up,
+            // so instead immediately send back a cancel and let the new task continue launched
+            // as normal without a dependency on its originator.
+            Slog.w(TAG, "Activity is launching as a new task, so cancelling activity result.");
+            mStartActivity.resultTo.task.stack.sendActivityResultLocked(-1, mStartActivity.resultTo,
+                    mStartActivity.resultWho, mStartActivity.requestCode, RESULT_CANCELED, null);
+            mStartActivity.resultTo = null;
+        }
+    }
+
+    private void computeLaunchingTaskFlags() {
+        // If the caller is not coming from another activity, but has given us an explicit task into
+        // which they would like us to launch the new activity, then let's see about doing that.
+        if (mSourceRecord == null && mInTask != null && mInTask.stack != null) {
+            final Intent baseIntent = mInTask.getBaseIntent();
+            final ActivityRecord root = mInTask.getRootActivity();
+            if (baseIntent == null) {
+                ActivityOptions.abort(mOptions);
+                throw new IllegalArgumentException("Launching into task without base intent: "
+                        + mInTask);
+            }
+
+            // If this task is empty, then we are adding the first activity -- it
+            // determines the root, and must be launching as a NEW_TASK.
+            if (mLaunchSingleInstance || mLaunchSingleTask) {
+                if (!baseIntent.getComponent().equals(mStartActivity.intent.getComponent())) {
+                    ActivityOptions.abort(mOptions);
+                    throw new IllegalArgumentException("Trying to launch singleInstance/Task "
+                            + mStartActivity + " into different task " + mInTask);
+                }
+                if (root != null) {
+                    ActivityOptions.abort(mOptions);
+                    throw new IllegalArgumentException("Caller with mInTask " + mInTask
+                            + " has root " + root + " but target is singleInstance/Task");
+                }
+            }
+
+            // If task is empty, then adopt the interesting intent launch flags in to the
+            // activity being started.
+            if (root == null) {
+                final int flagsOfInterest = FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK
+                        | FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+                mLaunchFlags = (mLaunchFlags & ~flagsOfInterest)
+                        | (baseIntent.getFlags() & flagsOfInterest);
+                mIntent.setFlags(mLaunchFlags);
+                mInTask.setIntent(mStartActivity);
+                mAddingToTask = true;
+
+                // If the task is not empty and the caller is asking to start it as the root of
+                // a new task, then we don't actually want to start this on the task. We will
+                // bring the task to the front, and possibly give it a new intent.
+            } else if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0) {
+                mAddingToTask = false;
+
+            } else {
+                mAddingToTask = true;
+            }
+
+            mReuseTask = mInTask;
+        } else {
+            mInTask = null;
+            // Launch ResolverActivity in the source task, so that it stays in the task bounds
+            // when in freeform workspace.
+            // Also put noDisplay activities in the source task. These by itself can be placed
+            // in any task/stack, however it could launch other activities like ResolverActivity,
+            // and we want those to stay in the original task.
+            if ((mStartActivity.isResolverActivity() || mStartActivity.noDisplay) && mSourceRecord != null
+                    && mSourceRecord.isFreeform())  {
+                mAddingToTask = true;
+            }
+        }
+
+        if (mInTask == null) {
+            if (mSourceRecord == null) {
+                // This activity is not being started from another...  in this
+                // case we -always- start a new task.
+                if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0 && mInTask == null) {
+                    Slog.w(TAG, "startActivity called from non-Activity context; forcing " +
+                            "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+                    mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+                }
+            } else if (mSourceRecord.launchMode == LAUNCH_SINGLE_INSTANCE) {
+                // The original activity who is starting us is running as a single
+                // instance...  this new activity it is starting must go on its
+                // own task.
+                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+            } else if (mLaunchSingleInstance || mLaunchSingleTask) {
+                // The activity being started is a single instance...  it always
+                // gets launched into its own task.
+                mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+            }
+        }
+    }
+
+    private void computeSourceStack() {
+        if (mSourceRecord == null) {
+            mSourceStack = null;
+            return;
+        }
+        if (!mSourceRecord.finishing) {
+            mSourceStack = mSourceRecord.task.stack;
+            return;
+        }
+
+        // If the source is finishing, we can't further count it as our source. This is because the
+        // task it is associated with may now be empty and on its way out, so we don't want to
+        // blindly throw it in to that task.  Instead we will take the NEW_TASK flow and try to find
+        // a task for it. But save the task information so it can be used when creating the new task.
+        if ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) == 0) {
+            Slog.w(TAG, "startActivity called from finishing " + mSourceRecord
+                    + "; forcing " + "Intent.FLAG_ACTIVITY_NEW_TASK for: " + mIntent);
+            mLaunchFlags |= FLAG_ACTIVITY_NEW_TASK;
+            mNewTaskInfo = mSourceRecord.info;
+            mNewTaskIntent = mSourceRecord.task.intent;
+        }
+        mSourceRecord = null;
+        mSourceStack = null;
+    }
+
+    /**
+     * Decide whether the new activity should be inserted into an existing task. Returns null
+     * if not or an ActivityRecord with the task into which the new activity should be added.
+     */
+    private ActivityRecord getReusableIntentActivity() {
+        // We may want to try to place the new activity in to an existing task.  We always
+        // do this if the target activity is singleTask or singleInstance; we will also do
+        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
+        // us to still place it in a new task: multi task, always doc mode, or being asked to
+        // launch this as a new task behind the current one.
+        boolean putIntoExistingTask = ((mLaunchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
+                (mLaunchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
+                || mLaunchSingleInstance || mLaunchSingleTask;
+        // If bring to front is requested, and no result is requested and we have not been given
+        // an explicit task to launch in to, and we can find a task that was started with this
+        // same component, then instead of launching bring that one to the front.
+        putIntoExistingTask &= mInTask == null && mStartActivity.resultTo == null;
+        ActivityRecord intentActivity = null;
+        if (putIntoExistingTask) {
+            // See if there is a task to bring to the front.  If this is a SINGLE_INSTANCE
+            // activity, there can be one and only one instance of it in the history, and it is
+            // always in its own unique task, so we do a special search.
+            intentActivity = mLaunchSingleInstance ? mSupervisor.findActivityLocked(mIntent, mStartActivity.info)
+                    : mSupervisor.findTaskLocked(mStartActivity);
+        }
+        return intentActivity;
+    }
+
+    private ActivityRecord setTargetStackAndMoveToFrontIfNeeded(ActivityRecord intentActivity) {
+        mTargetStack = intentActivity.task.stack;
+        mTargetStack.mLastPausedActivity = null;
+        // If the target task is not in the front, then we need to bring it to the front...
+        // except...  well, with SINGLE_TASK_LAUNCH it's not entirely clear. We'd like to have
+        // the same behavior as if a new instance was being started, which means not bringing it
+        // to the front if the caller is not itself in the front.
+        final ActivityStack focusStack = mSupervisor.getFocusedStack();
+        ActivityRecord curTop = (focusStack == null)
+                ? null : focusStack.topRunningNonDelayedActivityLocked(mNotTop);
+
+        if (curTop != null && (curTop.task != intentActivity.task ||
+                curTop.task != focusStack.topTask())) {
+            mStartActivity.intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT);
+            if (mSourceRecord == null || (mSourceStack.topActivity() != null &&
+                    mSourceStack.topActivity().task == mSourceRecord.task)) {
+                // We really do want to push this one into the user's face, right now.
+                if (mLaunchTaskBehind && mSourceRecord != null) {
+                    intentActivity.setTaskToAffiliateWith(mSourceRecord.task);
+                }
+                mMovedHome = true;
+                final ActivityStack launchStack =
+                        getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task,
+                                mOptions, true);
+                if (launchStack == null || launchStack == mTargetStack) {
+                    // We only want to move to the front, if we aren't going to launch on a
+                    // different stack. If we launch on a different stack, we will put the
+                    // task on top there.
+                    mTargetStack.moveTaskToFrontLocked(intentActivity.task, mNoAnimation,
+                            mOptions, mStartActivity.appTimeTracker, "bringingFoundTaskToFront");
+                    mMovedToFront = true;
+                }
+                if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME))
+                        == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_TASK_ON_HOME)) {
+                    // Caller wants to appear on home activity.
+                    intentActivity.task.setTaskToReturnTo(HOME_ACTIVITY_TYPE);
+                }
+                mOptions = null;
+            }
+        }
+        if (!mMovedToFront && mDoResume) {
+            if (DEBUG_TASKS) Slog.d(TAG_TASKS, "Bring to front target: " + mTargetStack
+                    + " from " + intentActivity);
+            mTargetStack.moveToFront("intentActivityFound");
+        }
+
+        // If the caller has requested that the target task be reset, then do so.
+        if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) != 0) {
+            return mTargetStack.resetTaskIfNeededLocked(intentActivity, mStartActivity);
+        }
+        return intentActivity;
+    }
+
+    private void setTaskFromIntentActivity(ActivityRecord intentActivity) {
+        if ((mLaunchFlags & (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK))
+                == (FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK)) {
+            // The caller has requested to completely replace any existing task with its new
+            // activity. Well that should not be too hard...
+            mReuseTask = intentActivity.task;
+            mReuseTask.performClearTaskLocked();
+            mReuseTask.setIntent(mStartActivity);
+        } else if ((mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0
+                || mLaunchSingleInstance || mLaunchSingleTask) {
+            // In this situation we want to remove all activities from the task up to the one
+            // being started. In most cases this means we are resetting the task to its initial
+            // state.
+            ActivityRecord top = intentActivity.task.performClearTaskLocked(mStartActivity,
+                    mLaunchFlags);
+            if (top != null) {
+                if (top.frontOfTask) {
+                    // Activity aliases may mean we use different intents for the top activity,
+                    // so make sure the task now has the identity of the new intent.
+                    top.task.setIntent(mStartActivity);
+                }
+                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task);
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+            } else {
+                // A special case: we need to start the activity because it is not currently
+                // running, and the caller has asked to clear the current task to have this
+                // activity at the top.
+                mAddingToTask = true;
+                // Now pretend like this activity is being started by the top of its task, so it
+                // is put in the right place.
+                mSourceRecord = intentActivity;
+                final TaskRecord task = mSourceRecord.task;
+                if (task != null && task.stack == null) {
+                    // Target stack got cleared when we all activities were removed above.
+                    // Go ahead and reset it.
+                    mTargetStack = computeStackFocus(mSourceRecord, false /* newTask */,
+                            null /* bounds */, mLaunchFlags, mOptions);
+                    mTargetStack.addTask(task,
+                            !mLaunchTaskBehind /* toTop */, "startActivityUnchecked");
+                }
+            }
+        } else if (mStartActivity.realActivity.equals(intentActivity.task.realActivity)) {
+            // In this case the top activity on the task is the same as the one being launched,
+            // so we take that as a request to bring the task to the foreground. If the top
+            // activity in the task is the root activity, deliver this new intent to it if it
+            // desires.
+            if (((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0 || mLaunchSingleTop)
+                    && intentActivity.realActivity.equals(mStartActivity.realActivity)) {
+                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity,
+                        intentActivity.task);
+                if (intentActivity.frontOfTask) {
+                    intentActivity.task.setIntent(mStartActivity);
+                }
+                intentActivity.deliverNewIntentLocked(mCallingUid, mStartActivity.intent,
+                        mStartActivity.launchedFromPackage);
+            } else if (!mStartActivity.intent.filterEquals(intentActivity.task.intent)) {
+                // In this case we are launching the root activity of the task, but with a
+                // different intent. We should start a new instance on top.
+                mAddingToTask = true;
+                mSourceRecord = intentActivity;
+            }
+        } else if ((mLaunchFlags & FLAG_ACTIVITY_RESET_TASK_IF_NEEDED) == 0) {
+            // In this case an activity is being launched in to an existing task, without
+            // resetting that task. This is typically the situation of launching an activity
+            // from a notification or shortcut. We want to place the new activity on top of the
+            // current task.
+            mAddingToTask = true;
+            mSourceRecord = intentActivity;
+        } else if (!intentActivity.task.rootWasReset) {
+            // In this case we are launching into an existing task that has not yet been started
+            // from its front door. The current task has been brought to the front. Ideally,
+            // we'd probably like to place this new task at the bottom of its stack, but that's
+            // a little hard to do with the current organization of the code so for now we'll
+            // just drop it.
+            intentActivity.task.setIntent(mStartActivity);
+        }
+    }
+
+    private void resumeTargetStackIfNeeded() {
+        if (mDoResume) {
+            mSupervisor.resumeFocusedStackTopActivityLocked(mTargetStack, null, mOptions);
+            if (!mMovedToFront) {
+                // Make sure to notify Keyguard as well if we are not running an app transition
+                // later.
+                mSupervisor.notifyActivityDrawnForKeyguard();
+            }
+        } else {
+            ActivityOptions.abort(mOptions);
+        }
+        mSupervisor.updateUserStackLocked(mStartActivity.userId, mTargetStack);
+    }
+
+    private void setTaskFromReuseOrCreateNewTask(TaskRecord taskToAffiliate) {
+        mTargetStack = computeStackFocus(mStartActivity, true, mLaunchBounds, mLaunchFlags,
+                mOptions);
+        if (mDoResume) {
+            mTargetStack.moveToFront("startingNewTask");
+        }
+
+        if (mReuseTask == null) {
+            final TaskRecord task = mTargetStack.createTaskRecord(mSupervisor.getNextTaskId(),
+                    mNewTaskInfo != null ? mNewTaskInfo : mStartActivity.info,
+                    mNewTaskIntent != null ? mNewTaskIntent : mIntent,
+                    mVoiceSession, mVoiceInteractor, !mLaunchTaskBehind /* toTop */);
+            mStartActivity.setTask(task, taskToAffiliate);
+            if (mLaunchBounds != null) {
+                mStartActivity.task.updateOverrideConfiguration(mLaunchBounds);
+            }
+            if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                    "Starting new activity " +
+                            mStartActivity + " in new task " + mStartActivity.task);
+        } else {
+            mStartActivity.setTask(mReuseTask, taskToAffiliate);
+        }
+    }
+
+    private int setTaskFromSourceRecord() {
+        final TaskRecord sourceTask = mSourceRecord.task;
+        // We only want to allow changing stack if the target task is not the top one,
+        // otherwise we would move the launching task to the other side, rather than show
+        // two side by side.
+        final boolean launchToSideAllowed = sourceTask.stack.topTask() != sourceTask;
+        mTargetStack = getLaunchStack(mStartActivity, mLaunchFlags, mStartActivity.task, mOptions, launchToSideAllowed);
+
+        if (mTargetStack == null) {
+            mTargetStack = sourceTask.stack;
+        } else if (mTargetStack != sourceTask.stack) {
+            mSupervisor.moveTaskToStackLocked(sourceTask.taskId, mTargetStack.mStackId,
+                    ON_TOP, FORCE_FOCUS, "launchToSide", !ANIMATE);
+        }
+        if (mDoResume) {
+            mTargetStack.moveToFront("sourceStackToFront");
+        }
+        final TaskRecord topTask = mTargetStack.topTask();
+        if (topTask != sourceTask) {
+            mTargetStack.moveTaskToFrontLocked(sourceTask, mNoAnimation, mOptions,
+                    mStartActivity.appTimeTracker, "sourceTaskToFront");
+        }
+        if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_CLEAR_TOP) != 0) {
+            // In this case, we are adding the activity to an existing task, but the caller has
+            // asked to clear that task if the activity is already running.
+            ActivityRecord top = sourceTask.performClearTaskLocked(mStartActivity, mLaunchFlags);
+            mKeepCurTransition = true;
+            if (top != null) {
+                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, top.task);
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+                // For paranoia, make sure we have correctly resumed the top activity.
+                mTargetStack.mLastPausedActivity = null;
+                if (mDoResume) {
+                    mSupervisor.resumeFocusedStackTopActivityLocked();
+                }
+                ActivityOptions.abort(mOptions);
+                return START_DELIVERED_TO_TOP;
+            }
+        } else if (!mAddingToTask && (mLaunchFlags & FLAG_ACTIVITY_REORDER_TO_FRONT) != 0) {
+            // In this case, we are launching an activity in our own task that may already be
+            // running somewhere in the history, and we want to shuffle it to the front of the
+            // stack if so.
+            final ActivityRecord top = sourceTask.findActivityInHistoryLocked(mStartActivity);
+            if (top != null) {
+                final TaskRecord task = top.task;
+                task.moveActivityToFrontLocked(top);
+                top.updateOptionsLocked(mOptions);
+                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, mStartActivity, task);
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+                mTargetStack.mLastPausedActivity = null;
+                if (mDoResume) {
+                    mSupervisor.resumeFocusedStackTopActivityLocked();
+                }
+                return START_DELIVERED_TO_TOP;
+            }
+        }
+
+        // An existing activity is starting this new activity, so we want to keep the new one in
+        // the same task as the one that is starting it.
+        mStartActivity.setTask(sourceTask, null);
+        if (DEBUG_TASKS) Slog.v(TAG_TASKS, "Starting new activity " + mStartActivity
+                + " in existing task " + mStartActivity.task + " from source " + mSourceRecord);
+        return START_SUCCESS;
+    }
+
+    private int setTaskFromInTask() {
+        if (mLaunchBounds != null) {
+            mInTask.updateOverrideConfiguration(mLaunchBounds);
+            int stackId = mInTask.getLaunchStackId();
+            if (stackId != mInTask.stack.mStackId) {
+                mSupervisor.moveTaskToStackUncheckedLocked(
+                        mInTask, stackId, ON_TOP, !FORCE_FOCUS, "inTaskToFront");
+            }
+        }
+        mTargetStack = mInTask.stack;
+        mTargetStack.moveTaskToFrontLocked(
+                mInTask, mNoAnimation, mOptions, mStartActivity.appTimeTracker, "inTaskToFront");
+
+        // Check whether we should actually launch the new activity in to the task,
+        // or just reuse the current activity on top.
+        ActivityRecord top = mInTask.getTopActivity();
+        if (top != null && top.realActivity.equals(mStartActivity.realActivity) && top.userId == mStartActivity.userId) {
+            if ((mLaunchFlags & FLAG_ACTIVITY_SINGLE_TOP) != 0
+                    || mLaunchSingleTop || mLaunchSingleTask) {
+                ActivityStack.logStartActivity(EventLogTags.AM_NEW_INTENT, top, top.task);
+                if ((mStartFlags & START_FLAG_ONLY_IF_NEEDED) != 0) {
+                    // We don't need to start a new activity, and the client said not to do
+                    // anything if that is the case, so this is it!
+                    return START_RETURN_INTENT_TO_CALLER;
+                }
+                top.deliverNewIntentLocked(mCallingUid, mStartActivity.intent, mStartActivity.launchedFromPackage);
+                return START_DELIVERED_TO_TOP;
+            }
+        }
+
+        if (!mAddingToTask) {
+            // We don't actually want to have this activity added to the task, so just
+            // stop here but still tell the caller that we consumed the intent.
+            ActivityOptions.abort(mOptions);
+            return START_TASK_TO_FRONT;
+        }
+
+        mStartActivity.setTask(mInTask, null);
+        if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                "Starting new activity " + mStartActivity + " in explicit task " + mStartActivity.task);
+
+        return START_SUCCESS;
+    }
+
+    private void setTaskToCurrentTopOrCreateNewTask() {
+        mTargetStack = computeStackFocus(mStartActivity, false, null /* bounds */, mLaunchFlags,
+                mOptions);
+        if (mDoResume) {
+            mTargetStack.moveToFront("addingToTopTask");
+        }
+        final ActivityRecord prev = mTargetStack.topActivity();
+        final TaskRecord task = prev != null ? prev.task
+                : mTargetStack.createTaskRecord(
+                mSupervisor.getNextTaskId(), mStartActivity.info, mIntent, null, null, true);
+        mStartActivity.setTask(task, null);
+        mWindowManager.moveTaskToTop(mStartActivity.task.taskId);
+        if (DEBUG_TASKS) Slog.v(TAG_TASKS,
+                "Starting new activity " + mStartActivity + " in new guessed " + mStartActivity.task);
+    }
+
+    private int adjustLaunchFlagsToDocumentMode(ActivityRecord r, boolean launchSingleInstance,
+            boolean launchSingleTask, int launchFlags) {
+        if ((launchFlags & Intent.FLAG_ACTIVITY_NEW_DOCUMENT) != 0 &&
+                (launchSingleInstance || launchSingleTask)) {
+            // We have a conflict between the Intent and the Activity manifest, manifest wins.
+            Slog.i(TAG, "Ignoring FLAG_ACTIVITY_NEW_DOCUMENT, launchMode is " +
+                    "\"singleInstance\" or \"singleTask\"");
+            launchFlags &=
+                    ~(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | FLAG_ACTIVITY_MULTIPLE_TASK);
+        } else {
+            switch (r.info.documentLaunchMode) {
+                case ActivityInfo.DOCUMENT_LAUNCH_NONE:
+                    break;
+                case ActivityInfo.DOCUMENT_LAUNCH_INTO_EXISTING:
+                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+                    break;
+                case ActivityInfo.DOCUMENT_LAUNCH_ALWAYS:
+                    launchFlags |= Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
+                    break;
+                case ActivityInfo.DOCUMENT_LAUNCH_NEVER:
+                    launchFlags &= ~FLAG_ACTIVITY_MULTIPLE_TASK;
+                    break;
+            }
+        }
+        return launchFlags;
     }
 
     final void doPendingActivityLaunchesLocked(boolean doResume) {
@@ -1389,9 +1568,8 @@
             PendingActivityLaunch pal = mPendingActivityLaunches.remove(0);
 
             try {
-                startActivityUncheckedLocked(pal.r, pal.sourceRecord, null, null,
-                        pal.startFlags, doResume && mPendingActivityLaunches.isEmpty(),
-                        null, null);
+                startActivityUnchecked(pal.r, pal.sourceRecord, null, null, pal.startFlags,
+                        doResume && mPendingActivityLaunches.isEmpty(), null, null);
             } catch (Exception e) {
                 Slog.e(TAG, "Exception during pending activity launch pal=" + pal, e);
                 pal.sendErrorResult(e.getMessage());
@@ -1400,13 +1578,13 @@
     }
 
     private ActivityStack computeStackFocus(ActivityRecord r, boolean newTask, Rect bounds,
-            int launchFlags) {
+            int launchFlags, ActivityOptions aOptions) {
         final TaskRecord task = r.task;
         if (!(r.isApplicationActivity() || (task != null && task.isApplicationTask()))) {
             return mSupervisor.mHomeStack;
         }
 
-        ActivityStack stack = getLaunchToSideStack(r, launchFlags, task);
+        ActivityStack stack = getLaunchStack(r, launchFlags, task, aOptions, true);
         if (stack != null) {
             return stack;
         }
@@ -1442,7 +1620,7 @@
         final boolean canUseFocusedStack =
                 focusedStackId == FULLSCREEN_WORKSPACE_STACK_ID
                         || focusedStackId == DOCKED_STACK_ID
-                        || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.info.resizeable);
+                        || (focusedStackId == FREEFORM_WORKSPACE_STACK_ID && r.isResizeable());
         if (canUseFocusedStack && (!newTask
                 || mSupervisor.mFocusedStack.mActivityContainer.isEligibleForNewTasks())) {
             if (DEBUG_FOCUS || DEBUG_STACK) Slog.d(TAG_FOCUS,
@@ -1471,10 +1649,19 @@
         return stack;
     }
 
-    private ActivityStack getLaunchToSideStack(ActivityRecord r, int launchFlags, TaskRecord task) {
-        if ((launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
+    private ActivityStack getLaunchStack(ActivityRecord r, int launchFlags, TaskRecord task,
+            ActivityOptions aOptions, boolean launchToSideAllowed) {
+        final int launchStackId =
+                (aOptions != null) ? aOptions.getLaunchStackId() : INVALID_STACK_ID;
+
+        if (isValidLaunchStackId(launchStackId, r)) {
+            return mSupervisor.getStack(launchStackId, CREATE_IF_NEEDED, ON_TOP);
+        }
+
+        if (!launchToSideAllowed || (launchFlags & FLAG_ACTIVITY_LAUNCH_TO_SIDE) == 0) {
             return null;
         }
+
         // The parent activity doesn't want to launch the activity on top of itself, but
         // instead tries to put it onto other side in side-by-side mode.
         final ActivityStack parentStack = task != null ? task.stack
@@ -1498,36 +1685,39 @@
         }
     }
 
-    /**
-     * Decide whether the new activity should be inserted into an existing task. Returns null if not
-     * or an ActivityRecord with the task into which the new activity should be added.
-     */
-    private ActivityRecord getReusableIntentActivity(ActivityRecord r, TaskRecord inTask,
-            Intent intent, boolean launchSingleInstance, boolean launchSingleTask,
-            int launchFlags) {
-        // We may want to try to place the new activity in to an existing task.  We always
-        // do this if the target activity is singleTask or singleInstance; we will also do
-        // this if NEW_TASK has been requested, and there is not an additional qualifier telling
-        // us to still place it in a new task: multi task, always doc mode, or being asked to
-        // launch this as a new task behind the current one.
-        boolean putIntoExistingTask = ((launchFlags & FLAG_ACTIVITY_NEW_TASK) != 0 &&
-                (launchFlags & FLAG_ACTIVITY_MULTIPLE_TASK) == 0)
-                || launchSingleInstance || launchSingleTask;
-        // If bring to front is requested, and no result is requested and we have not
-        // been given an explicit task to launch in to, and
-        // we can find a task that was started with this same
-        // component, then instead of launching bring that one to the front.
-        putIntoExistingTask &= inTask == null && r.resultTo == null;
-        ActivityRecord intentActivity = null;
-        if (putIntoExistingTask) {
-            // See if there is a task to bring to the front.  If this is
-            // a SINGLE_INSTANCE activity, there can be one and only one
-            // instance of it in the history, and it is always in its own
-            // unique task, so we do a special search.
-            intentActivity = launchSingleInstance ? mSupervisor.findActivityLocked(intent, r.info)
-                    : mSupervisor.findTaskLocked(r);
+    private boolean isValidLaunchStackId(int stackId, ActivityRecord r) {
+        if (stackId == INVALID_STACK_ID || stackId == HOME_STACK_ID
+                || !StackId.isStaticStack(stackId)) {
+            return false;
         }
-        return intentActivity;
+
+        final boolean resizeable = r.isResizeable() || mService.mForceResizableActivities;
+
+        if (stackId != FULLSCREEN_WORKSPACE_STACK_ID && !resizeable) {
+            return false;
+        }
+
+        if (stackId == FREEFORM_WORKSPACE_STACK_ID && !mService.mSupportsFreeformWindowManagement) {
+            return false;
+        }
+
+        final boolean supportsPip = mService.mSupportsPictureInPicture
+                && (r.supportsPictureInPicture() || mService.mForceResizableActivities);
+        if (stackId == PINNED_STACK_ID && !supportsPip) {
+            return false;
+        }
+        return true;
+    }
+
+    Rect getOverrideBounds(ActivityRecord r, ActivityOptions options, TaskRecord inTask) {
+        Rect newBounds = null;
+        if (options != null && (r.isResizeable() || (inTask != null && inTask.mResizeable))) {
+            if (mSupervisor.canUseActivityOptionsLaunchBounds(
+                    options, options.getLaunchStackId())) {
+                newBounds = options.getLaunchBounds();
+            }
+        }
+        return newBounds;
     }
 
     void setWindowManager(WindowManagerService wm) {
diff --git a/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
new file mode 100644
index 0000000..ff39589
--- /dev/null
+++ b/services/core/java/com/android/server/am/ResizeDockedStackTimeout.java
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.am;
+
+import android.graphics.Rect;
+import android.os.Handler;
+
+import static com.android.server.am.ActivityStackSupervisor.PRESERVE_WINDOWS;
+
+/**
+ * When resizing the docked stack, a caller can temporarily supply task bounds that are different
+ * from the stack bounds. In order to return to a sane state if the caller crashes or has a bug,
+ * this class manages this cycle.
+ */
+class ResizeDockedStackTimeout {
+
+    private static final long TIMEOUT_MS = 10 * 1000;
+    private final ActivityManagerService mService;
+    private final ActivityStackSupervisor mSupervisor;
+    private final Handler mHandler;
+    private final Rect mCurrentDockedBounds = new Rect();
+
+    private final Runnable mTimeoutRunnable = new Runnable() {
+        @Override
+        public void run() {
+            synchronized (mService) {
+                mSupervisor.resizeDockedStackLocked(mCurrentDockedBounds, null, null, null, null,
+                        PRESERVE_WINDOWS);
+            }
+        }
+    };
+
+    ResizeDockedStackTimeout(ActivityManagerService service, ActivityStackSupervisor supervisor,
+            Handler handler) {
+        mService = service;
+        mSupervisor = supervisor;
+        mHandler = handler;
+    }
+
+    void notifyResizing(Rect dockedBounds, boolean hasTempBounds) {
+        mHandler.removeCallbacks(mTimeoutRunnable);
+        if (!hasTempBounds) {
+            return;
+        }
+        mCurrentDockedBounds.set(dockedBounds);
+        mHandler.postDelayed(mTimeoutRunnable, TIMEOUT_MS);
+    }
+
+}
diff --git a/services/core/java/com/android/server/am/TaskRecord.java b/services/core/java/com/android/server/am/TaskRecord.java
index 4647d77..c97d09c 100644
--- a/services/core/java/com/android/server/am/TaskRecord.java
+++ b/services/core/java/com/android/server/am/TaskRecord.java
@@ -23,6 +23,7 @@
 import static android.app.ActivityManager.StackId.PINNED_STACK_ID;
 import static android.content.Intent.FLAG_ACTIVITY_NEW_DOCUMENT;
 import static android.content.Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS;
+import static android.content.pm.ActivityInfo.FLAG_RESIZEABLE;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_ALWAYS;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_DEFAULT;
 import static android.content.pm.ActivityInfo.LOCK_TASK_LAUNCH_MODE_IF_WHITELISTED;
@@ -441,7 +442,7 @@
         } else {
             autoRemoveRecents = false;
         }
-        mResizeable = info.resizeable || mService.mForceResizableActivities;
+        mResizeable = (info.flags & FLAG_RESIZEABLE) != 0 || mService.mForceResizableActivities;
         mLockTaskMode = info.lockTaskLaunchMode;
         mPrivileged = (info.applicationInfo.privateFlags & PRIVATE_FLAG_PRIVILEGED) != 0;
         setLockTaskAuth();
@@ -697,7 +698,7 @@
         if (mActivities.isEmpty()) {
             taskType = r.mActivityType;
             if (taskType == HOME_ACTIVITY_TYPE && mService.mForceResizableActivities) {
-                mResizeable = r.info.resizeable;
+                mResizeable = r.isResizeable();
             }
             isPersistable = r.isPersistable();
             mCallingUid = r.launchedFromUid;
@@ -1321,7 +1322,12 @@
         }
     }
 
-    void reportPictureInPictureModeChange() {
+    void reportPictureInPictureModeChangeIfNeeded(ActivityStack prevStack) {
+        if (prevStack == null || prevStack == stack
+                || (prevStack.mStackId != PINNED_STACK_ID && stack.mStackId != PINNED_STACK_ID)) {
+            return;
+        }
+
         for (int i = mActivities.size() - 1; i >= 0; i--) {
             final ActivityRecord r = mActivities.get(i);
             if (r.app != null && r.app.thread != null) {
diff --git a/services/core/java/com/android/server/am/UserController.java b/services/core/java/com/android/server/am/UserController.java
index 20b1e60..7172859 100644
--- a/services/core/java/com/android/server/am/UserController.java
+++ b/services/core/java/com/android/server/am/UserController.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityManager.USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
 import static android.app.ActivityManager.USER_OP_IS_CURRENT;
 import static android.app.ActivityManager.USER_OP_SUCCESS;
+import static android.content.Context.KEYGUARD_SERVICE;
 import static android.os.Process.SYSTEM_UID;
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_MU;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
@@ -43,6 +44,7 @@
 import android.app.Dialog;
 import android.app.IStopUserCallback;
 import android.app.IUserSwitchObserver;
+import android.app.KeyguardManager;
 import android.content.Context;
 import android.content.IIntentReceiver;
 import android.content.Intent;
@@ -73,6 +75,7 @@
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.ArrayUtils;
+import com.android.internal.widget.LockPatternUtils;
 import com.android.server.pm.UserManagerService;
 
 import java.io.PrintWriter;
@@ -304,7 +307,10 @@
                         + relatedUserId);
                 // We still need to stop the requested user if it's a force stop.
                 if (force) {
+                    Slog.i(TAG,
+                            "Force stop user " + userId + ". Related users will not be stopped");
                     stopSingleUserLocked(userId, callback);
+                    return USER_OP_SUCCESS;
                 }
                 return USER_OP_ERROR_RELATED_USERS_CANNOT_STOP;
             }
@@ -931,7 +937,7 @@
         if (homeInFront) {
             mService.startHomeActivityLocked(newUserId, "moveUserToForeground");
         } else {
-            mService.mStackSupervisor.resumeTopActivitiesLocked();
+            mService.mStackSupervisor.resumeFocusedStackTopActivityLocked();
         }
         EventLogTags.writeAmSwitchUser(newUserId);
         getUserManager().onUserForeground(newUserId);
@@ -1283,6 +1289,20 @@
         return mCurrentProfileIds;
     }
 
+    /**
+     * Returns whether the given user requires credential entry at this time. This is used to
+     * intercept activity launches for work apps when the Work Challenge is present.
+     */
+    boolean shouldConfirmCredentials(int userId) {
+        final UserInfo user = getUserInfo(userId);
+        if (!user.isManagedProfile() || !LockPatternUtils.isSeparateWorkChallengeEnabled()) {
+            return false;
+        }
+        final KeyguardManager km = (KeyguardManager) mService.mContext
+                .getSystemService(KEYGUARD_SERVICE);
+        return km.isDeviceLocked(user.id);
+    }
+
     void dump(PrintWriter pw, boolean dumpAll) {
         pw.println("  mStartedUsers:");
         for (int i = 0; i < mStartedUsers.size(); i++) {
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index c5e6e7c..4eabe36 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -161,8 +161,9 @@
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
-            Slog.d(TAG, "Receieved: " + intent.getAction());
-            if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
+            final String action = intent.getAction();
+            Slog.d(TAG, "Receieved: " + action);
+            if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
                 // If this is an outright uninstall rather than the first half of an
                 // app update sequence, cancel the jobs associated with the app.
                 if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
@@ -172,18 +173,21 @@
                     }
                     cancelJobsForUid(uidRemoved, true);
                 }
-            } else if (Intent.ACTION_USER_REMOVED.equals(intent.getAction())) {
+            } else if (Intent.ACTION_USER_REMOVED.equals(action)) {
                 final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0);
                 if (DEBUG) {
                     Slog.d(TAG, "Removing jobs for user: " + userId);
                 }
                 cancelJobsForUser(userId);
-            } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())
-                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(intent.getAction())) {
+            } else if (PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED.equals(action)
+                    || PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED.equals(action)) {
                 updateIdleMode(mPowerManager != null
                         ? (mPowerManager.isDeviceIdleMode()
                                 || mPowerManager.isLightDeviceIdleMode())
                         : false);
+            } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
+                // Kick off pending jobs for any apps that re-appeared
+                mHandler.obtainMessage(MSG_CHECK_JOB).sendToTarget();
             }
         }
     };
@@ -425,17 +429,24 @@
     @Override
     public void onBootPhase(int phase) {
         if (PHASE_SYSTEM_SERVICES_READY == phase) {
-            // Register br for package removals and user removals.
+            // Register for package removals and user removals.
             final IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_REMOVED);
             filter.addDataScheme("package");
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, filter, null, null);
+
             final IntentFilter userFilter = new IntentFilter(Intent.ACTION_USER_REMOVED);
             userFilter.addAction(PowerManager.ACTION_DEVICE_IDLE_MODE_CHANGED);
             userFilter.addAction(PowerManager.ACTION_LIGHT_DEVICE_IDLE_MODE_CHANGED);
             getContext().registerReceiverAsUser(
                     mBroadcastReceiver, UserHandle.ALL, userFilter, null, null);
-            mPowerManager = (PowerManager)getContext().getSystemService(Context.POWER_SERVICE);
+
+            final IntentFilter storageFilter = new IntentFilter();
+            storageFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
+            getContext().registerReceiverAsUser(
+                    mBroadcastReceiver, UserHandle.ALL, storageFilter, null, null);
+
+            mPowerManager = getContext().getSystemService(PowerManager.class);
             try {
                 ActivityManagerNative.getDefault().registerUidObserver(mUidObserver,
                         ActivityManager.UID_OBSERVER_IDLE);
@@ -834,7 +845,7 @@
             final boolean componentPresent;
             try {
                 componentPresent = (AppGlobals.getPackageManager().getServiceInfo(
-                        job.getServiceComponent(), PackageManager.MATCH_ENCRYPTION_DEFAULT,
+                        job.getServiceComponent(), PackageManager.MATCH_DEBUG_TRIAGED_MISSING,
                         userId) != null);
             } catch (RemoteException e) {
                 throw e.rethrowAsRuntimeException();
@@ -924,8 +935,8 @@
             final IPackageManager pm = AppGlobals.getPackageManager();
             final ComponentName service = job.getService();
             try {
-                ServiceInfo si = pm.getServiceInfo(service, PackageManager.MATCH_ENCRYPTION_DEFAULT,
-                        UserHandle.getUserId(uid));
+                ServiceInfo si = pm.getServiceInfo(service,
+                        PackageManager.MATCH_DEBUG_TRIAGED_MISSING, UserHandle.getUserId(uid));
                 if (si == null) {
                     throw new IllegalArgumentException("No such service " + service);
                 }
diff --git a/services/core/java/com/android/server/notification/ConditionProviders.java b/services/core/java/com/android/server/notification/ConditionProviders.java
index 1987214..ce18818 100644
--- a/services/core/java/com/android/server/notification/ConditionProviders.java
+++ b/services/core/java/com/android/server/notification/ConditionProviders.java
@@ -121,6 +121,11 @@
     }
 
     @Override
+    protected boolean checkType(IInterface service) {
+        return service instanceof IConditionProvider;
+    }
+
+    @Override
     public void onBootPhaseAppsCanStart() {
         super.onBootPhaseAppsCanStart();
         for (int i = 0; i < mSystemConditionProviders.size(); i++) {
diff --git a/services/core/java/com/android/server/notification/ManagedServices.java b/services/core/java/com/android/server/notification/ManagedServices.java
index b7662da..09e6647 100644
--- a/services/core/java/com/android/server/notification/ManagedServices.java
+++ b/services/core/java/com/android/server/notification/ManagedServices.java
@@ -141,6 +141,8 @@
 
     abstract protected IInterface asInterface(IBinder binder);
 
+    abstract protected boolean checkType(IInterface service);
+
     abstract protected void onServiceAdded(ManagedServiceInfo info);
 
     protected void onServiceRemovedLocked(ManagedServiceInfo removed) { }
@@ -169,7 +171,8 @@
             if (filter != null && !filter.matches(info.component)) continue;
             pw.println("      " + info.component
                     + " (user " + info.userid + "): " + info.service
-                    + (info.isSystem?" SYSTEM":""));
+                    + (info.isSystem?" SYSTEM":"")
+                    + (info.isGuest(this)?" GUEST":""));
         }
     }
 
@@ -266,6 +269,18 @@
         }
     }
 
+    /**
+     * Add a service to our callbacks. The lifecycle of this service is managed externally,
+     * but unlike a system service, it should not be considered privledged.
+     * */
+    public void registerGuestService(ManagedServiceInfo guest) {
+        checkNotNull(guest.service);
+        checkType(guest.service);
+        if (registerServiceImpl(guest) != null) {
+            onServiceAdded(guest);
+        }
+    }
+
     public void setCategoryState(String category, boolean enabled) {
         synchronized (mMutex) {
             final Boolean previous = mCategoryEnabled.put(category, enabled);
@@ -484,7 +499,7 @@
         synchronized (mMutex) {
             // Unbind automatically bound services, retain system services.
             for (ManagedServiceInfo service : mServices) {
-                if (!service.isSystem) {
+                if (!service.isSystem && !service.isGuest(this)) {
                     toRemove.add(service);
                 }
             }
@@ -709,11 +724,15 @@
 
     private ManagedServiceInfo registerServiceImpl(final IInterface service,
             final ComponentName component, final int userid) {
+        ManagedServiceInfo info = newServiceInfo(service, component, userid,
+                true /*isSystem*/, null /*connection*/, Build.VERSION_CODES.LOLLIPOP);
+        return registerServiceImpl(info);
+    }
+
+    private ManagedServiceInfo registerServiceImpl(ManagedServiceInfo info) {
         synchronized (mMutex) {
             try {
-                ManagedServiceInfo info = newServiceInfo(service, component, userid,
-                        true /*isSystem*/, null, Build.VERSION_CODES.LOLLIPOP);
-                service.asBinder().linkToDeath(info, 0);
+                info.service.asBinder().linkToDeath(info, 0);
                 mServices.add(info);
                 return info;
             } catch (RemoteException e) {
@@ -728,7 +747,7 @@
      */
     private void unregisterServiceImpl(IInterface service, int userid) {
         ManagedServiceInfo info = removeServiceImpl(service, userid);
-        if (info != null && info.connection != null) {
+        if (info != null && info.connection != null && !info.isGuest(this)) {
             mContext.unbindService(info.connection);
         }
     }
@@ -780,6 +799,10 @@
             this.targetSdkVersion = targetSdkVersion;
         }
 
+        public boolean isGuest(ManagedServices host) {
+            return ManagedServices.this != host;
+        }
+
         @Override
         public String toString() {
             return new StringBuilder("ManagedServiceInfo[")
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 49aa73e..8657049 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -33,12 +33,14 @@
 import static android.service.notification.NotificationListenerService.Ranking.IMPORTANCE_HIGH;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_LIGHTS;
 import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_PEEK;
+import static android.service.notification.NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON;
 import static android.service.notification.NotificationListenerService.TRIM_FULL;
 import static android.service.notification.NotificationListenerService.TRIM_LIGHT;
 import static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;
 import static org.xmlpull.v1.XmlPullParser.END_TAG;
 import static org.xmlpull.v1.XmlPullParser.START_TAG;
 
+import android.Manifest;
 import android.app.ActivityManager;
 import android.app.ActivityManagerNative;
 import android.app.AppGlobals;
@@ -96,6 +98,7 @@
 import android.service.notification.IConditionProvider;
 import android.service.notification.INotificationListener;
 import android.service.notification.IStatusBarNotificationHolder;
+import android.service.notification.NotificationAssistantService;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationRankingUpdate;
 import android.service.notification.StatusBarNotification;
@@ -154,6 +157,7 @@
 import java.util.List;
 import java.util.Map.Entry;
 import java.util.Objects;
+import java.util.concurrent.TimeUnit;
 
 /** {@hide} */
 public class NotificationManagerService extends SystemService {
@@ -167,11 +171,13 @@
     // message codes
     static final int MESSAGE_TIMEOUT = 2;
     static final int MESSAGE_SAVE_POLICY_FILE = 3;
-    static final int MESSAGE_RECONSIDER_RANKING = 4;
-    static final int MESSAGE_RANKING_CONFIG_CHANGE = 5;
-    static final int MESSAGE_SEND_RANKING_UPDATE = 6;
-    static final int MESSAGE_LISTENER_HINTS_CHANGED = 7;
-    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 8;
+    static final int MESSAGE_SEND_RANKING_UPDATE = 4;
+    static final int MESSAGE_LISTENER_HINTS_CHANGED = 5;
+    static final int MESSAGE_LISTENER_NOTIFICATION_FILTER_CHANGED = 6;
+
+    // ranking thread messages
+    private static final int MESSAGE_RECONSIDER_RANKING = 1000;
+    private static final int MESSAGE_RANKING_SORT = 1001;
 
     static final int LONG_DELAY = 3500; // 3.5 seconds
     static final int SHORT_DELAY = 2000; // 2 seconds
@@ -281,11 +287,13 @@
 
     private final UserProfiles mUserProfiles = new UserProfiles();
     private NotificationListeners mListeners;
+    private NotificationAssistant mAssistant;
     private ConditionProviders mConditionProviders;
     private NotificationUsageStats mUsageStats;
 
     private static final int MY_UID = Process.myUid();
     private static final int MY_PID = Process.myPid();
+    private RankingHandler mRankingHandler;
 
     private static class Archive {
         final int mBufferSize;
@@ -738,6 +746,7 @@
                     }
                 }
                 mListeners.onPackagesChanged(queryReplace, pkgList);
+                mAssistant.onPackagesChanged(queryReplace, pkgList);
                 mConditionProviders.onPackagesChanged(queryReplace, pkgList);
                 mRankingHelper.onPackagesChanged(queryReplace, pkgList);
             }
@@ -779,6 +788,7 @@
                 // Refresh managed services
                 mConditionProviders.onUserSwitched(user);
                 mListeners.onUserSwitched(user);
+                mAssistant.onUserSwitched(user);
                 mZenModeHelper.onUserSwitched(user);
             } else if (action.equals(Intent.ACTION_USER_ADDED)) {
                 mUserProfiles.updateCache(context);
@@ -874,8 +884,9 @@
             extractorNames = new String[0];
         }
         mUsageStats = new NotificationUsageStats(getContext());
+        mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
         mRankingHelper = new RankingHelper(getContext(),
-                new RankingWorkerHandler(mRankingThread.getLooper()),
+                mRankingHandler,
                 mUsageStats,
                 extractorNames);
         mConditionProviders = new ConditionProviders(getContext(), mHandler, mUserProfiles);
@@ -909,6 +920,7 @@
         importOldBlockDb();
 
         mListeners = new NotificationListeners();
+        mAssistant = new NotificationAssistant();
         mStatusBar = getLocalService(StatusBarManagerInternal.class);
         mStatusBar.setNotificationDelegate(mNotificationDelegate);
 
@@ -1025,6 +1037,7 @@
             // bind to listener services.
             mSettingsObserver.observe();
             mListeners.onBootPhaseAppsCanStart();
+            mAssistant.onBootPhaseAppsCanStart();
             mConditionProviders.onBootPhaseAppsCanStart();
         }
     }
@@ -1896,6 +1909,22 @@
                 Binder.restoreCallingIdentity(identity);
             }
         }
+
+        @Override
+        public void setImportanceFromAssistant(INotificationListener token, String key,
+                int importance, CharSequence explanation) {
+            final long identity = Binder.clearCallingIdentity();
+            try {
+                synchronized (mNotificationList) {
+                    mAssistant.checkServiceTokenLocked(token);
+                    NotificationRecord n = mNotificationsByKey.get(key);
+                    n.setImportance(importance, explanation);
+                    mRankingHandler.requestSort();
+                }
+            } finally {
+                Binder.restoreCallingIdentity(identity);
+            }
+        }
     };
 
     private String disableNotificationEffects(NotificationRecord record) {
@@ -2037,6 +2066,8 @@
                     pw.print(listener.component);
                 }
                 pw.println(')');
+                pw.println("\n  Notification assistant:");
+                mAssistant.dump(pw, filter);
             }
             pw.println("\n  Policy access:");
             pw.print("    mPolicyAccess: "); pw.println(mPolicyAccess);
@@ -2533,9 +2564,14 @@
             updateLightsLocked();
         }
         if (buzz || beep || blink) {
-            EventLogTags.writeNotificationAlert(record.getKey(),
-                    buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
-            mHandler.post(mBuzzBeepBlinked);
+            if (((record.getSuppressedVisualEffects()
+                    & NotificationListenerService.SUPPRESSED_EFFECT_SCREEN_ON) != 0)) {
+                if (DBG) Slog.v(TAG, "Suppressed SystemUI from triggering screen on");
+            } else {
+                EventLogTags.writeNotificationAlert(record.getKey(),
+                        buzz ? 1 : 0, beep ? 1 : 0, blink ? 1 : 0);
+                mHandler.post(mBuzzBeepBlinked);
+            }
         }
     }
 
@@ -2686,7 +2722,7 @@
         }
     }
 
-    private void handleRankingConfigChange() {
+    private void handleRankingSort() {
         synchronized (mNotificationList) {
             final int N = mNotificationList.size();
             ArrayList<String> orderBefore = new ArrayList<String>(N);
@@ -2714,7 +2750,8 @@
         record.setIntercepted(mZenModeHelper.shouldIntercept(record));
         if (record.isIntercepted()) {
             int suppressed = (mZenModeHelper.shouldSuppressLight() ? SUPPRESSED_EFFECT_LIGHTS : 0)
-                    | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0);
+                    | (mZenModeHelper.shouldSuppressPeek() ? SUPPRESSED_EFFECT_PEEK : 0)
+                    | (mZenModeHelper.shouldSuppressScreenOn() ? SUPPRESSED_EFFECT_SCREEN_ON : 0);
             record.setSuppressedVisualEffects(suppressed);
         }
     }
@@ -2788,9 +2825,9 @@
 
     }
 
-    private final class RankingWorkerHandler extends Handler
+    private final class RankingHandlerWorker extends Handler implements RankingHandler
     {
-        public RankingWorkerHandler(Looper looper) {
+        public RankingHandlerWorker(Looper looper) {
             super(looper);
         }
 
@@ -2800,11 +2837,23 @@
                 case MESSAGE_RECONSIDER_RANKING:
                     handleRankingReconsideration(msg);
                     break;
-                case MESSAGE_RANKING_CONFIG_CHANGE:
-                    handleRankingConfigChange();
+                case MESSAGE_RANKING_SORT:
+                    handleRankingSort();
                     break;
             }
         }
+
+        public void requestSort() {
+            removeMessages(MESSAGE_RANKING_SORT);
+            sendEmptyMessage(MESSAGE_RANKING_SORT);
+        }
+
+        public void requestReconsideration(RankingReconsideration recon) {
+            Message m = Message.obtain(this,
+                    NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
+            long delay = recon.getDelay(TimeUnit.MILLISECONDS);
+            sendMessageDelayed(m, delay);
+        }
     }
 
     // Notifications
@@ -3305,6 +3354,45 @@
         return true;
     }
 
+    public class NotificationAssistant extends ManagedServices {
+
+        public NotificationAssistant() {
+            super(getContext(), mHandler, mNotificationList, mUserProfiles);
+        }
+
+        @Override
+        protected Config getConfig() {
+            Config c = new Config();
+            c.caption = "notification assistant";
+            c.serviceInterface = NotificationAssistantService.SERVICE_INTERFACE;
+            c.secureSettingName = Settings.Secure.ENABLED_NOTIFICATION_ASSISTANT;
+            c.bindPermission = Manifest.permission.BIND_NOTIFICATION_ASSISTANT_SERVICE;
+            c.settingsAction = Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS;
+            c.clientLabel = R.string.notification_assistant_binding_label;
+            return c;
+        }
+
+        @Override
+        protected IInterface asInterface(IBinder binder) {
+            return INotificationListener.Stub.asInterface(binder);
+        }
+
+        @Override
+        protected boolean checkType(IInterface service) {
+            return service instanceof INotificationListener;
+        }
+
+        @Override
+        protected void onServiceAdded(ManagedServiceInfo info) {
+            mListeners.registerGuestService(info);
+        }
+
+        @Override
+        protected void onServiceRemovedLocked(ManagedServiceInfo removed) {
+            mListeners.unregisterService(removed.service, removed.userid);
+        }
+    }
+
     public class NotificationListeners extends ManagedServices {
 
         private final ArraySet<ManagedServiceInfo> mLightTrimListeners = new ArraySet<>();
@@ -3332,6 +3420,11 @@
         }
 
         @Override
+        protected boolean checkType(IInterface service) {
+            return service instanceof INotificationListener;
+        }
+
+        @Override
         public void onServiceAdded(ManagedServiceInfo info) {
             final INotificationListener listener = (INotificationListener) info.service;
             final NotificationRankingUpdate update;
@@ -3366,7 +3459,6 @@
 
         public int getOnNotificationPostedTrim(ManagedServiceInfo info) {
             return mLightTrimListeners.contains(info) ? TRIM_LIGHT : TRIM_FULL;
-
         }
 
         /**
diff --git a/core/java/android/service/notification/NotificationAdjustment.aidl b/services/core/java/com/android/server/notification/RankingHandler.java
similarity index 77%
rename from core/java/android/service/notification/NotificationAdjustment.aidl
rename to services/core/java/com/android/server/notification/RankingHandler.java
index 805fe2c..80bb4f0 100644
--- a/core/java/android/service/notification/NotificationAdjustment.aidl
+++ b/services/core/java/com/android/server/notification/RankingHandler.java
@@ -13,7 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+package com.android.server.notification;
 
-package android.service.notification;
-
-parcelable NotificationAdjustment;
\ No newline at end of file
+public interface RankingHandler {
+    public void requestSort();
+    public void requestReconsideration(RankingReconsideration recon);
+}
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index 3287f67..0662e7a 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -19,10 +19,7 @@
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.os.Handler;
-import android.os.Message;
 import android.os.UserHandle;
-import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationListenerService.Ranking;
 import android.text.TextUtils;
 import android.util.ArrayMap;
@@ -40,7 +37,6 @@
 import java.util.Collections;
 import java.util.List;
 import java.util.Map;
-import java.util.concurrent.TimeUnit;
 
 public class RankingHelper implements RankingConfig {
     private static final String TAG = "RankingHelper";
@@ -73,10 +69,10 @@
     private final ArrayMap<String, Record> mRestoredWithoutUids = new ArrayMap<>(); // pkg => Record
 
     private final Context mContext;
-    private final Handler mRankingHandler;
+    private final RankingHandler mRankingHandler;
 
-    public RankingHelper(Context context, Handler rankingHandler, NotificationUsageStats usageStats,
-            String[] extractorNames) {
+    public RankingHelper(Context context, RankingHandler rankingHandler,
+            NotificationUsageStats usageStats, String[] extractorNames) {
         mContext = context;
         mRankingHandler = rankingHandler;
 
@@ -119,10 +115,7 @@
             try {
                 RankingReconsideration recon = extractor.process(r);
                 if (recon != null) {
-                    Message m = Message.obtain(mRankingHandler,
-                            NotificationManagerService.MESSAGE_RECONSIDER_RANKING, recon);
-                    long delay = recon.getDelay(TimeUnit.MILLISECONDS);
-                    mRankingHandler.sendMessageDelayed(m, delay);
+                    mRankingHandler.requestReconsideration(recon);
                 }
             } catch (Throwable t) {
                 Slog.w(TAG, "NotificationSignalExtractor failed.", t);
@@ -287,7 +280,7 @@
         for (int i = 0; i < N; i++) {
             mSignalExtractors[i].setConfig(this);
         }
-        mRankingHandler.sendEmptyMessage(NotificationManagerService.MESSAGE_RANKING_CONFIG_CHANGE);
+        mRankingHandler.requestSort();
     }
 
     public void sort(ArrayList<NotificationRecord> notificationList) {
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index 85c3cf8..276c6ba 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -155,6 +155,12 @@
         }
     }
 
+    public boolean shouldSuppressScreenOn() {
+        synchronized (mConfig) {
+            return !mConfig.allowScreenOn;
+        }
+    }
+
     public void addCallback(Callback callback) {
         mCallbacks.add(callback);
     }
@@ -435,11 +441,12 @@
             return;
         }
         pw.printf("allow(calls=%s,callsFrom=%s,repeatCallers=%s,messages=%s,messagesFrom=%s,"
-                + "events=%s,reminders=%s,lights=%s,peek=%s)\n",
+                + "events=%s,reminders=%s,lights=%s,peek=%s,screenOn=%s)\n",
                 config.allowCalls, ZenModeConfig.sourceToString(config.allowCallsFrom),
                 config.allowRepeatCallers, config.allowMessages,
                 ZenModeConfig.sourceToString(config.allowMessagesFrom),
-                config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek);
+                config.allowEvents, config.allowReminders, config.allowLights, config.allowPeek,
+                config.allowScreenOn);
         pw.print(prefix); pw.print("  manualRule="); pw.println(config.manualRule);
         if (config.automaticRules.isEmpty()) return;
         final int N = config.automaticRules.size();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 7bb6d1d..7e186a0 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -106,6 +106,7 @@
 import android.content.pm.ActivityInfo;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.AppsQueryHelper;
+import android.content.pm.ComponentInfo;
 import android.content.pm.EphemeralApplicationInfo;
 import android.content.pm.EphemeralResolveInfo;
 import android.content.pm.EphemeralResolveInfo.EphemeralResolveIntentInfo;
@@ -122,7 +123,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageCleanItem;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInfoLite;
@@ -207,7 +207,6 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.IMediaContainerService;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.content.NativeLibraryHelper;
@@ -308,7 +307,7 @@
     private static final boolean DEBUG_DEXOPT = false;
     private static final boolean DEBUG_ABI_SELECTION = false;
     private static final boolean DEBUG_EPHEMERAL = false;
-    private static final boolean DEBUG_ENCRYPTION_AWARE = false;
+    private static final boolean DEBUG_TRIAGED_MISSING = false;
 
     static final boolean CLEAR_RUNTIME_PERMISSIONS_ON_UPGRADE = false;
 
@@ -2848,6 +2847,7 @@
     @Override
     public PackageInfo getPackageInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package info");
         // reader
         synchronized (mPackages) {
@@ -2898,6 +2898,7 @@
     @Override
     public int getPackageUidEtc(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return -1;
+        flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get package uid");
 
         // reader
@@ -2924,10 +2925,8 @@
 
     @Override
     public int[] getPackageGidsEtc(String packageName, int flags, int userId) {
-        if (!sUserManager.exists(userId)) {
-            return null;
-        }
-
+        if (!sUserManager.exists(userId)) return null;
+        flags = updateFlagsForPackage(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false,
                 "getPackageGids");
 
@@ -2949,8 +2948,7 @@
         return null;
     }
 
-    static PermissionInfo generatePermissionInfo(
-            BasePermission bp, int flags) {
+    static PermissionInfo generatePermissionInfo(BasePermission bp, int flags) {
         if (bp.perm != null) {
             return PackageParser.generatePermissionInfo(bp.perm, flags);
         }
@@ -3068,6 +3066,7 @@
     @Override
     public ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
+        flags = updateFlagsForApplication(flags, userId, packageName);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get application info");
         // writer
         synchronized (mPackages) {
@@ -3182,46 +3181,88 @@
     }
 
     /**
-     * Augment the given flags depending on current user running state. This is
-     * purposefully done before acquiring {@link #mPackages} lock.
+     * Update given flags based on encryption status of current user.
      */
-    private int augmentFlagsForUser(int flags, int userId, Object cookie) {
-        if (cookie instanceof Intent) {
-            // If intent claims to be triaged, then we're fine with default
-            // matching behavior below
-            final Intent intent = (Intent) cookie;
-            if ((intent.getFlags() & Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED) != 0) {
-                flags |= PackageManager.MATCH_ENCRYPTION_DEFAULT;
-            }
-        }
-
-        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE_ONLY
-                | PackageManager.MATCH_ENCRYPTION_AWARE_ONLY)) != 0) {
-            // Caller expressed an opinion about what components they want to
-            // see, so fall through and give them what they want
+    private int updateFlagsForEncryption(int flags, int userId) {
+        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                | PackageManager.MATCH_ENCRYPTION_AWARE)) != 0) {
+            // Caller expressed an explicit opinion about what encryption
+            // aware/unaware components they want to see, so fall through and
+            // give them what they want
         } else {
             // Caller expressed no opinion, so match based on user state
             if (isUserKeyUnlocked(userId)) {
                 flags |= PackageManager.MATCH_ENCRYPTION_AWARE_AND_UNAWARE;
             } else {
-                flags |= PackageManager.MATCH_ENCRYPTION_AWARE_ONLY;
-
-                // If we have a system caller that hasn't done their homework to
-                // decide they want this default behavior, yell at them
-                if (DEBUG_ENCRYPTION_AWARE && (Binder.getCallingUid() == Process.SYSTEM_UID)
-                        && ((flags & PackageManager.MATCH_ENCRYPTION_DEFAULT) == 0)) {
-                    Log.v(TAG, "Caller hasn't been triaged for FBE; they asked about " + cookie,
-                            new Throwable());
-                }
+                flags |= PackageManager.MATCH_ENCRYPTION_AWARE;
             }
         }
         return flags;
     }
 
+    /**
+     * Update given flags when being used to request {@link PackageInfo}.
+     */
+    private int updateFlagsForPackage(int flags, int userId, Object cookie) {
+        boolean triaged = true;
+        if ((flags & PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS
+                | PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS) != 0) {
+            // Caller is asking for component details, so they'd better be
+            // asking for specific encryption matching behavior, or be triaged
+            if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                    | PackageManager.MATCH_ENCRYPTION_AWARE
+                    | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+                triaged = false;
+            }
+        }
+        if ((flags & (PackageManager.MATCH_UNINSTALLED_PACKAGES
+                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+            triaged = false;
+        }
+        if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+                    new Throwable());
+        }
+        return updateFlagsForEncryption(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ApplicationInfo}.
+     */
+    private int updateFlagsForApplication(int flags, int userId, Object cookie) {
+        return updateFlagsForPackage(flags, userId, cookie);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ComponentInfo}.
+     */
+    private int updateFlagsForComponent(int flags, int userId, Object cookie) {
+        boolean triaged = true;
+        // Caller is asking for component details, so they'd better be
+        // asking for specific encryption matching behavior, or be triaged
+        if ((flags & (PackageManager.MATCH_ENCRYPTION_UNAWARE
+                | PackageManager.MATCH_ENCRYPTION_AWARE
+                | PackageManager.MATCH_DEBUG_TRIAGED_MISSING)) == 0) {
+            triaged = false;
+        }
+        if (DEBUG_TRIAGED_MISSING && (Binder.getCallingUid() == Process.SYSTEM_UID) && !triaged) {
+            Log.w(TAG, "Caller hasn't been triaged for missing apps; they asked about " + cookie,
+                    new Throwable());
+        }
+        return updateFlagsForEncryption(flags, userId);
+    }
+
+    /**
+     * Update given flags when being used to request {@link ResolveInfo}.
+     */
+    private int updateFlagsForResolve(int flags, int userId, Object cookie) {
+        return updateFlagsForComponent(flags, userId, cookie);
+    }
+
     @Override
     public ActivityInfo getActivityInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get activity info");
         synchronized (mPackages) {
             PackageParser.Activity a = mActivities.mActivities.get(component);
@@ -3266,7 +3307,7 @@
     @Override
     public ActivityInfo getReceiverInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get receiver info");
         synchronized (mPackages) {
             PackageParser.Activity a = mReceivers.mActivities.get(component);
@@ -3285,7 +3326,7 @@
     @Override
     public ServiceInfo getServiceInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get service info");
         synchronized (mPackages) {
             PackageParser.Service s = mServices.mServices.get(component);
@@ -3304,7 +3345,7 @@
     @Override
     public ProviderInfo getProviderInfo(ComponentName component, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, component);
+        flags = updateFlagsForComponent(flags, userId, component);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "get provider info");
         synchronized (mPackages) {
             PackageParser.Provider p = mProviders.mProviders.get(component);
@@ -4429,7 +4470,7 @@
     public ResolveInfo resolveIntent(Intent intent, String resolvedType,
             int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "resolve intent");
         List<ResolveInfo> query = queryIntentActivities(intent, resolvedType, flags, userId);
         final ResolveInfo bestChoice =
@@ -4687,7 +4728,7 @@
             List<ResolveInfo> query, int priority, boolean always,
             boolean removeMatches, boolean debug, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         // writer
         synchronized (mPackages) {
             if (intent.getSelector() != null) {
@@ -4886,7 +4927,7 @@
     public List<ResolveInfo> queryIntentActivities(Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false, false, "query intent activities");
         ComponentName comp = intent.getComponent();
         if (comp == null) {
@@ -5370,7 +5411,7 @@
             Intent[] specifics, String[] specificTypes, Intent intent,
             String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         enforceCrossUserPermission(Binder.getCallingUid(), userId, false,
                 false, "query intent activity options");
         final String resultsAction = intent.getAction();
@@ -5543,7 +5584,7 @@
     public List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5580,7 +5621,7 @@
     @Override
     public ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         List<ResolveInfo> query = queryIntentServices(intent, resolvedType, flags, userId);
         if (query != null) {
             if (query.size() >= 1) {
@@ -5596,7 +5637,7 @@
     public List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags,
             int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5634,7 +5675,7 @@
     public List<ResolveInfo> queryIntentContentProviders(
             Intent intent, String resolvedType, int flags, int userId) {
         if (!sUserManager.exists(userId)) return Collections.emptyList();
-        flags = augmentFlagsForUser(flags, userId, intent);
+        flags = updateFlagsForResolve(flags, userId, intent);
         ComponentName comp = intent.getComponent();
         if (comp == null) {
             if (intent.getSelector() != null) {
@@ -5670,8 +5711,9 @@
 
     @Override
     public ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) {
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForPackage(flags, userId, null);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
-
         enforceCrossUserPermission(Binder.getCallingUid(), userId, true, false, "get installed packages");
 
         // writer
@@ -5750,7 +5792,8 @@
     @Override
     public ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(
             String[] permissions, int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForPackage(flags, userId, permissions);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
 
         // writer
@@ -5777,7 +5820,8 @@
 
     @Override
     public ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) {
-        if (!sUserManager.exists(userId)) return null;
+        if (!sUserManager.exists(userId)) return ParceledListSlice.emptyList();
+        flags = updateFlagsForApplication(flags, userId, null);
         final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0;
 
         // writer
@@ -5920,7 +5964,7 @@
     @Override
     public ProviderInfo resolveContentProvider(String name, int flags, int userId) {
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, name);
+        flags = updateFlagsForComponent(flags, userId, name);
         // reader
         synchronized (mPackages) {
             final PackageParser.Provider provider = mProvidersByAuthority.get(name);
@@ -5972,7 +6016,7 @@
         final int userId = processName != null ? UserHandle.getUserId(uid)
                 : UserHandle.getCallingUserId();
         if (!sUserManager.exists(userId)) return null;
-        flags = augmentFlagsForUser(flags, userId, processName);
+        flags = updateFlagsForComponent(flags, userId, processName);
 
         ArrayList<ProviderInfo> finalList = null;
         // reader
@@ -6009,8 +6053,7 @@
     }
 
     @Override
-    public InstrumentationInfo getInstrumentationInfo(ComponentName name,
-            int flags) {
+    public InstrumentationInfo getInstrumentationInfo(ComponentName name, int flags) {
         // reader
         synchronized (mPackages) {
             final PackageParser.Instrumentation i = mInstrumentation.get(name);
@@ -6205,7 +6248,6 @@
 
         try {
             pp.collectCertificates(pkg, parseFlags);
-            pp.collectManifestDigest(pkg);
         } catch (PackageParserException e) {
             throw PackageManagerException.from(e);
         }
@@ -10037,7 +10079,7 @@
         }
         final VerificationParams verifParams = new VerificationParams(
                 null, sessionParams.originatingUri, sessionParams.referrerUri,
-                sessionParams.originatingUid, null);
+                sessionParams.originatingUid);
         verifParams.setInstallerUid(installerUid);
 
         final OriginInfo origin;
@@ -11019,13 +11061,6 @@
                     + " file=" + origin.file + " cid=" + origin.cid + "}";
         }
 
-        public ManifestDigest getManifestDigest() {
-            if (verificationParams == null) {
-                return null;
-            }
-            return verificationParams.getManifestDigest();
-        }
-
         private int installLocationPolicy(PackageInfoLite pkgLite) {
             String packageName = pkgLite.packageName;
             int installLocation = pkgLite.installLocation;
@@ -11444,7 +11479,6 @@
         final int installFlags;
         final String installerPackageName;
         final String volumeUuid;
-        final ManifestDigest manifestDigest;
         final UserHandle user;
         final String abiOverride;
         final String[] installGrantPermissions;
@@ -11459,7 +11493,7 @@
 
         InstallArgs(OriginInfo origin, MoveInfo move, IPackageInstallObserver2 observer,
                 int installFlags, String installerPackageName, String volumeUuid,
-                ManifestDigest manifestDigest, UserHandle user, String[] instructionSets,
+                UserHandle user, String[] instructionSets,
                 String abiOverride, String[] installGrantPermissions,
                 String traceMethod, int traceCookie) {
             this.origin = origin;
@@ -11468,7 +11502,6 @@
             this.observer = observer;
             this.installerPackageName = installerPackageName;
             this.volumeUuid = volumeUuid;
-            this.manifestDigest = manifestDigest;
             this.user = user;
             this.instructionSets = instructionSets;
             this.abiOverride = abiOverride;
@@ -11570,7 +11603,7 @@
         /** New install */
         FileInstallArgs(InstallParams params) {
             super(params.origin, params.move, params.observer, params.installFlags,
-                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie);
@@ -11581,7 +11614,7 @@
 
         /** Existing install */
         FileInstallArgs(String codePath, String resourcePath, String[] instructionSets) {
-            super(OriginInfo.fromNothing(), null, null, 0, null, null, null, null, instructionSets,
+            super(OriginInfo.fromNothing(), null, null, 0, null, null, null, instructionSets,
                     null, null, null, 0);
             this.codeFile = (codePath != null) ? new File(codePath) : null;
             this.resourceFile = (resourcePath != null) ? new File(resourcePath) : null;
@@ -11808,7 +11841,7 @@
         /** New install */
         AsecInstallArgs(InstallParams params) {
             super(params.origin, params.move, params.observer, params.installFlags,
-                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie);
@@ -11818,7 +11851,7 @@
         AsecInstallArgs(String fullCodePath, String[] instructionSets,
                         boolean isExternal, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, null, (isExternal ? INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
                     instructionSets, null, null, null, 0);
             // Hackily pretend we're still looking at a full code path
             if (!fullCodePath.endsWith(RES_FILE_NAME)) {
@@ -11835,7 +11868,7 @@
 
         AsecInstallArgs(String cid, String[] instructionSets, boolean isForwardLocked) {
             super(OriginInfo.fromNothing(), null, null, (isAsecExternal(cid) ? INSTALL_EXTERNAL : 0)
-                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null, null,
+                    | (isForwardLocked ? INSTALL_FORWARD_LOCK : 0), null, null, null,
                     instructionSets, null, null, null, 0);
             this.cid = cid;
             setMountPath(PackageHelper.getSdDir(cid));
@@ -12102,7 +12135,7 @@
         /** New install */
         MoveInstallArgs(InstallParams params) {
             super(params.origin, params.move, params.observer, params.installFlags,
-                    params.installerPackageName, params.volumeUuid, params.getManifestDigest(),
+                    params.installerPackageName, params.volumeUuid,
                     params.getUser(), null /* instruction sets */, params.packageAbiOverride,
                     params.grantedRuntimePermissions,
                     params.traceMethod, params.traceCookie);
@@ -12876,35 +12909,6 @@
             Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
         }
 
-        /* If the installer passed in a manifest digest, compare it now. */
-        if (args.manifestDigest != null) {
-            Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "collectManifestDigest");
-            try {
-                pp.collectManifestDigest(pkg);
-            } catch (PackageParserException e) {
-                res.setError("Failed collect during installPackageLI", e);
-                return;
-            } finally {
-                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
-            }
-
-            if (DEBUG_INSTALL) {
-                final String parsedManifest = pkg.manifestDigest == null ? "null"
-                        : pkg.manifestDigest.toString();
-                Slog.d(TAG, "Comparing manifests: " + args.manifestDigest.toString() + " vs. "
-                        + parsedManifest);
-            }
-
-            if (!args.manifestDigest.equals(pkg.manifestDigest)) {
-                res.setError(INSTALL_FAILED_PACKAGE_CHANGED, "Manifest digest changed");
-                return;
-            }
-        } else if (DEBUG_INSTALL) {
-            final String parsedManifest = pkg.manifestDigest == null
-                    ? "null" : pkg.manifestDigest.toString();
-            Slog.d(TAG, "manifestDigest was not present, but parser got: " + parsedManifest);
-        }
-
         // Get rid of all references to package scan path via parser.
         pp = null;
         String oldCodePath = null;
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index d2a3ede..b330139 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -3846,9 +3846,9 @@
             }
         }
 
-        final boolean matchesUnaware = ((flags & PackageManager.MATCH_ENCRYPTION_UNAWARE_ONLY) != 0)
+        final boolean matchesUnaware = ((flags & PackageManager.MATCH_ENCRYPTION_UNAWARE) != 0)
                 && !componentInfo.encryptionAware;
-        final boolean matchesAware = ((flags & PackageManager.MATCH_ENCRYPTION_AWARE_ONLY) != 0)
+        final boolean matchesAware = ((flags & PackageManager.MATCH_ENCRYPTION_AWARE) != 0)
                 && componentInfo.encryptionAware;
         return matchesUnaware || matchesAware;
     }
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 13f4826..3d614a3 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -69,6 +69,7 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.IAppOpsService;
+import com.android.internal.logging.MetricsLogger;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
@@ -166,6 +167,10 @@
 
     private static final String XATTR_SERIAL = "user.serial";
 
+    // Tron counters
+    private static final String TRON_GUEST_CREATED = "users_guest_created";
+    private static final String TRON_USER_CREATED = "users_user_created";
+
     private final Context mContext;
     private final PackageManagerService mPm;
     private final Object mPackagesLock;
@@ -1830,6 +1835,7 @@
             addedIntent.putExtra(Intent.EXTRA_USER_HANDLE, userId);
             mContext.sendBroadcastAsUser(addedIntent, UserHandle.ALL,
                     android.Manifest.permission.MANAGE_USERS);
+            MetricsLogger.count(mContext, isGuest ? TRON_GUEST_CREATED : TRON_USER_CREATED, 1);
         } finally {
             Binder.restoreCallingIdentity(ident);
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 6fcf1d6..72611b7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3381,7 +3381,6 @@
             if (awakenFromDreams) {
                 awakenDreams();
             }
-            sendCloseSystemWindows(SYSTEM_DIALOG_REASON_HOME_KEY);
             hideRecentApps(false, true);
         } else {
             // Otherwise, just launch Home
@@ -4243,6 +4242,7 @@
                         && (sysUiFl & View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION) != 0
                         && (attrs.type == TYPE_STATUS_BAR
                             || attrs.type == TYPE_TOAST
+                            || attrs.type == TYPE_DOCK_DIVIDER
                             || attrs.type == TYPE_VOICE_INTERACTION_STARTING
                             || (attrs.type >= WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW
                             && attrs.type <= WindowManager.LayoutParams.LAST_SUB_WINDOW))) {
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
index 29e3c63..549d2dc 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardServiceDelegate.java
@@ -126,7 +126,7 @@
 
         final ComponentName keyguardComponent = ComponentName.unflattenFromString(
                 resources.getString(com.android.internal.R.string.config_keyguardComponent));
-        intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         intent.setComponent(keyguardComponent);
 
         if (!context.bindServiceAsUser(intent, mKeyguardConnection,
diff --git a/services/core/java/com/android/server/wm/AppWindowToken.java b/services/core/java/com/android/server/wm/AppWindowToken.java
index b49641f..573aaec 100644
--- a/services/core/java/com/android/server/wm/AppWindowToken.java
+++ b/services/core/java/com/android/server/wm/AppWindowToken.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import static android.app.ActivityManager.StackId;
 import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
@@ -30,6 +31,7 @@
 
 import android.annotation.NonNull;
 import android.content.pm.ActivityInfo;
+import android.graphics.Rect;
 import android.os.Message;
 import android.os.RemoteException;
 import android.util.Slog;
@@ -38,6 +40,7 @@
 import android.view.WindowManager;
 
 import java.io.PrintWriter;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 
 class AppTokenList extends ArrayList<AppWindowToken> {
@@ -123,6 +126,10 @@
     // True if the windows associated with this token should be cropped to their stack bounds.
     boolean mCropWindowsToStack;
 
+    boolean mAlwaysFocusable;
+
+    ArrayDeque<Rect> mFrozenBounds = new ArrayDeque<>();
+
     AppWindowToken(WindowManagerService _service, IApplicationToken _token,
             boolean _voiceInteraction) {
         super(_service, _token.asBinder(),
@@ -256,8 +263,8 @@
         return candidate;
     }
 
-    boolean stackCanReceiveKeys() {
-        return (windows.size() > 0) ? windows.get(windows.size() - 1).stackCanReceiveKeys() : false;
+    boolean windowsAreFocusable() {
+        return StackId.canReceiveKeys(mTask.mStack.mStackId) || mAlwaysFocusable;
     }
 
     boolean isVisible() {
@@ -434,6 +441,23 @@
         }
     }
 
+    /**
+     * Freezes the task bounds. The size of this task reported the app will be fixed to the bounds
+     * freezed by {@link Task#prepareFreezingBounds} until {@link #unfreezeBounds} gets called, even
+     * if they change in the meantime. If the bounds are already frozen, the bounds will be frozen
+     * with a queue.
+     */
+    void freezeBounds() {
+        mFrozenBounds.offer(new Rect(mTask.mPreparedFrozenBounds));
+    }
+
+    /**
+     * Unfreezes the previously frozen bounds. See {@link #freezeBounds}.
+     */
+    void unfreezeBounds() {
+        mFrozenBounds.remove();
+    }
+
     @Override
     void dump(PrintWriter pw, String prefix) {
         super.dump(pw, prefix);
@@ -480,6 +504,9 @@
                     pw.print(" startingDisplayed="); pw.print(startingDisplayed);
                     pw.print(" startingMoved"); pw.println(startingMoved);
         }
+        if (!mFrozenBounds.isEmpty()) {
+            pw.print(prefix); pw.print("mFrozenBounds="); pw.print(mFrozenBounds);
+        }
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DockedStackDividerController.java b/services/core/java/com/android/server/wm/DockedStackDividerController.java
index 8f3d3e3..7295318 100644
--- a/services/core/java/com/android/server/wm/DockedStackDividerController.java
+++ b/services/core/java/com/android/server/wm/DockedStackDividerController.java
@@ -18,11 +18,17 @@
 
 import android.content.Context;
 import android.graphics.Rect;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.util.Slog;
-import android.view.IDockDividerVisibilityListener;
+import android.view.DisplayInfo;
+import android.view.IDockedStackListener;
+import android.view.SurfaceControl;
+
+import com.android.server.wm.DimLayer.DimLayerUser;
 
 import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.INVALID_STACK_ID;
 import static android.view.WindowManager.DOCKED_BOTTOM;
 import static android.view.WindowManager.DOCKED_LEFT;
 import static android.view.WindowManager.DOCKED_RIGHT;
@@ -33,7 +39,7 @@
 /**
  * Keeps information about the docked stack divider.
  */
-public class DockedStackDividerController {
+public class DockedStackDividerController implements DimLayerUser {
 
     private static final String TAG = TAG_WITH_CLASS_NAME ? "DockedStackDividerController" : TAG_WM;
 
@@ -44,9 +50,10 @@
     private WindowState mWindow;
     private final Rect mTmpRect = new Rect();
     private final Rect mLastRect = new Rect();
-    private IDockDividerVisibilityListener mListener;
     private boolean mLastVisibility = false;
-    private boolean mForceVisibilityReevaluation;
+    private final RemoteCallbackList<IDockedStackListener> mDockedStackListeners
+            = new RemoteCallbackList<>();
+    private final DimLayer mDimLayer;
 
     DockedStackDividerController(Context context, DisplayContent displayContent) {
         mDisplayContent = displayContent;
@@ -54,6 +61,7 @@
                 com.android.internal.R.dimen.docked_stack_divider_thickness);
         mDividerInsets = context.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.docked_stack_divider_insets);
+        mDimLayer = new DimLayer(displayContent.mService, this, displayContent.getDisplayId());
     }
 
     boolean isResizing() {
@@ -83,15 +91,16 @@
             return;
         }
         mLastVisibility = visible;
-        if (mListener != null) {
-            try {
-                mListener.onDockDividerVisibilityChanged(visible);
-            } catch (RemoteException e) {
-                Slog.e(TAG, "visibility call failed: " + e);
-            }
+        notifyDockedDividerVisibilityChanged(visible);
+        if (!visible) {
+            setResizeDimLayer(false, INVALID_STACK_ID, 0f);
         }
     }
 
+    boolean wasVisible() {
+        return mLastVisibility;
+    }
+
     void positionDockedStackedDivider(Rect frame) {
         TaskStack stack = mDisplayContent.getDockedStackLocked();
         if (stack == null) {
@@ -127,11 +136,76 @@
         mLastRect.set(frame);
     }
 
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
-        if (mListener != null && listener != null) {
-            throw new IllegalStateException("Dock divider visibility listener already set!");
+    void notifyDockedDividerVisibilityChanged(boolean visible) {
+        final int size = mDockedStackListeners.beginBroadcast();
+        for (int i = 0; i < size; ++i) {
+            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+            try {
+                listener.onDividerVisibilityChanged(visible);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering divider visibility changed event.", e);
+            }
         }
-        mListener = listener;
-        reevaluateVisibility(true);
+        mDockedStackListeners.finishBroadcast();
+    }
+
+    void notifyDockedStackExistsChanged(boolean exists) {
+        final int size = mDockedStackListeners.beginBroadcast();
+        for (int i = 0; i < size; ++i) {
+            final IDockedStackListener listener = mDockedStackListeners.getBroadcastItem(i);
+            try {
+                listener.onDockedStackExistsChanged(exists);
+            } catch (RemoteException e) {
+                Slog.e(TAG_WM, "Error delivering docked stack exists changed event.", e);
+            }
+        }
+        mDockedStackListeners.finishBroadcast();
+    }
+
+    void registerDockedStackListener(IDockedStackListener listener) {
+        mDockedStackListeners.register(listener);
+        notifyDockedDividerVisibilityChanged(wasVisible());
+        notifyDockedStackExistsChanged(
+                mDisplayContent.mService.mStackIdToStack.get(DOCKED_STACK_ID) != null);
+    }
+
+    void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+        SurfaceControl.openTransaction();
+        TaskStack stack = mDisplayContent.mService.mStackIdToStack.get(targetStackId);
+        boolean visibleAndValid = visible && stack != null;
+        if (visibleAndValid) {
+            stack.getDimBounds(mTmpRect);
+            if (mTmpRect.height() > 0 && mTmpRect.width() > 0) {
+                mDimLayer.setBounds(mTmpRect);
+                mDimLayer.show(mDisplayContent.mService.mLayersController.getResizeDimLayer(),
+                        alpha, 0 /* duration */);
+            } else {
+                visibleAndValid = false;
+            }
+        }
+        if (!visibleAndValid) {
+            mDimLayer.hide();
+        }
+        SurfaceControl.closeTransaction();
+    }
+
+    @Override
+    public boolean isFullscreen() {
+        return false;
+    }
+
+    @Override
+    public DisplayInfo getDisplayInfo() {
+        return mDisplayContent.getDisplayInfo();
+    }
+
+    @Override
+    public void getDimBounds(Rect outBounds) {
+        // This dim layer user doesn't need this.
+    }
+
+    @Override
+    public String toShortString() {
+        return TAG;
     }
 }
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 27e7a31..223e03a 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -61,6 +61,10 @@
 
     // Content limits relative to the DisplayContent this sits in.
     private Rect mBounds = new Rect();
+    final Rect mPreparedFrozenBounds = new Rect();
+
+    // Bounds used to calculate the insets.
+    private final Rect mTempInsetBounds = new Rect();
 
     // Device rotation as of the last time {@link #mBounds} was set.
     int mRotation;
@@ -197,8 +201,7 @@
     boolean removeAppToken(AppWindowToken wtoken) {
         boolean removed = mAppTokens.remove(wtoken);
         if (mAppTokens.size() == 0) {
-            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId,
-                    "removeAppToken: last token");
+            EventLog.writeEvent(EventLogTags.WM_TASK_REMOVED, mTaskId, "removeAppToken: last token");
             if (mDeferRemoval) {
                 removeLocked();
             }
@@ -267,6 +270,26 @@
         return boundsChange;
     }
 
+    /**
+     * Sets the bounds used to calculate the insets. See
+     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+     */
+    void setTempInsetBounds(Rect tempInsetBounds) {
+        if (tempInsetBounds != null) {
+            mTempInsetBounds.set(tempInsetBounds);
+        } else {
+            mTempInsetBounds.setEmpty();
+        }
+    }
+
+    /**
+     * Gets the bounds used to calculate the insets. See
+     * {@link android.app.IActivityManager#resizeDockedStack} why this is needed.
+     */
+    void getTempInsetBounds(Rect out) {
+        out.set(mTempInsetBounds);
+    }
+
     void setResizeable(boolean resizeable) {
         mResizeable = resizeable;
     }
@@ -291,6 +314,14 @@
         return true;
     }
 
+    /**
+     * Prepares the task bounds to be frozen with the current size. See
+     * {@link AppWindowToken#freezeBounds}.
+     */
+    void prepareFreezingBounds() {
+        mPreparedFrozenBounds.set(mBounds);
+    }
+
     boolean scrollLocked(Rect bounds) {
         // shift the task bound if it doesn't fully cover the stack area
         mStack.getDimBounds(mTmpRect);
@@ -357,7 +388,6 @@
         mStack.getDisplayContent().getLogicalDisplayRect(out);
     }
 
-
     /**
      * Calculate the maximum visible area of this task. If the task has only one app,
      * the result will be visible frame of that app. If the task has more than one apps,
@@ -579,5 +609,6 @@
             pw.print(prefix + prefix); pw.print("mBounds="); pw.println(mBounds.toShortString());
             pw.print(prefix + prefix); pw.print("mdr="); pw.println(mDeferRemoval);
             pw.print(prefix + prefix); pw.print("appTokens="); pw.println(mAppTokens);
+            pw.print(prefix + prefix); pw.print("mTempInsetBounds="); pw.println(mTempInsetBounds);
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index b961879..67debe6 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -114,7 +114,8 @@
      * @return True if the stack bounds was changed.
      * */
     boolean setBounds(
-            Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+            Rect stackBounds, SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
         if (!setBounds(stackBounds)) {
             return false;
         }
@@ -136,6 +137,9 @@
                     task.scrollLocked(mTmpRect);
                 } else {
                     task.setBounds(bounds, config);
+                    task.setTempInsetBounds(
+                            taskTempInsetBounds != null ? taskTempInsetBounds.get(task.mTaskId)
+                                    : null);
                 }
             } else {
                 Slog.wtf(TAG_WM, "No config for task: " + task + ", is there a mismatch with AM?");
@@ -144,6 +148,13 @@
         return true;
     }
 
+    void prepareFreezingTaskBounds() {
+        for (int taskNdx = mTasks.size() - 1; taskNdx >= 0; --taskNdx) {
+            final Task task = mTasks.get(taskNdx);
+            task.prepareFreezingBounds();
+        }
+    }
+
     boolean isFullscreenBounds(Rect bounds) {
         if (mDisplayContent == null || bounds == null) {
             return true;
diff --git a/services/core/java/com/android/server/wm/WindowLayersController.java b/services/core/java/com/android/server/wm/WindowLayersController.java
index 263b411..2cf2618 100644
--- a/services/core/java/com/android/server/wm/WindowLayersController.java
+++ b/services/core/java/com/android/server/wm/WindowLayersController.java
@@ -1,9 +1,20 @@
-package com.android.server.wm;
+/*
+ * 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.
+ */
 
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
+package com.android.server.wm;
 
 import android.app.ActivityManager.StackId;
 import android.util.Slog;
@@ -11,6 +22,11 @@
 
 import java.io.PrintWriter;
 
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYERS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerService.WINDOW_LAYER_MULTIPLIER;
+
 /**
  * Controller for assigning layers to windows on the display.
  *
@@ -42,7 +58,6 @@
     private WindowState mPinnedWindow = null;
     private WindowState mDockedWindow = null;
     private WindowState mDockDivider = null;
-    private WindowState mImeWindow = null;
     private WindowState mReplacingWindow = null;
 
     final void assignLayersLocked(WindowList windows) {
@@ -133,6 +148,14 @@
         return 0;
     }
 
+    /**
+     * @return The layer used for dimming the apps when dismissing docked/fullscreen stack. Just
+     *         above all application surfaces.
+     */
+    int getResizeDimLayer() {
+        return mDockDivider.mLayer - 1;
+    }
+
     private void logDebugLayers(WindowList windows) {
         for (int i = 0, n = windows.size(); i < n; i++) {
             final WindowState w = windows.get(i);
@@ -146,16 +169,13 @@
 
     private void clear() {
         mHighestApplicationLayer = 0;
-        mImeWindow = null;
         mPinnedWindow = null;
         mDockedWindow = null;
         mDockDivider = null;
     }
 
     private void collectSpecialWindows(WindowState w) {
-        if (w.mIsImWindow) {
-            mImeWindow = w;
-        } else if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
+        if (w.mAttrs.type == TYPE_DOCK_DIVIDER) {
             mDockDivider = w;
         } else {
             final TaskStack stack = w.getStack();
@@ -175,18 +195,17 @@
         // For pinned and docked stack window, we want to make them above other windows
         // also when these windows are animating.
         layer = assignAndIncreaseLayerIfNeeded(mDockedWindow, layer);
+
+        // Leave some space here so the dim layer while dismissing docked/fullscreen stack has space
+        // below the divider but above the app windows. It needs to be below the divider in because
+        // the divider sometimes overlaps the app windows.
+        layer++;
         layer = assignAndIncreaseLayerIfNeeded(mDockDivider, layer);
         // We know that we will be animating a relaunching window in the near future,
         // which will receive a z-order increase. We want the replaced window to
         // immediately receive the same treatment, e.g. to be above the dock divider.
         layer = assignAndIncreaseLayerIfNeeded(mReplacingWindow, layer);
         layer = assignAndIncreaseLayerIfNeeded(mPinnedWindow, layer);
-        final WindowState inputMethodTarget = mService.mInputMethodTarget;
-        // There might be no applications windows yet, so we need to make sure we uplift the input
-        // method above the target.
-        layer = Math.max(layer,
-                inputMethodTarget != null ? inputMethodTarget.mWinAnimator.mAnimLayer + 1 : 0);
-        layer = assignAndIncreaseLayerIfNeeded(mImeWindow, layer);
     }
 
     private int assignAndIncreaseLayerIfNeeded(WindowState win, int layer) {
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 6385caa..d722ec7 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -16,81 +16,11 @@
 
 package com.android.server.wm;
 
-import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
-import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
-import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
-import static android.app.StatusBarManager.DISABLE_MASK;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
-import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
-import static android.view.WindowManager.DOCKED_INVALID;
-import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
-import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
-import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
-import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
-import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
-import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
-import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
-import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
-import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
-import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
-import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
-import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
-import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
-import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
-import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
-import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
-import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
-import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
-import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
-import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
-import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
-import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
-import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
-import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
-import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-
 import android.Manifest;
 import android.animation.ValueAnimator;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.ActivityManager.StackId;
 import android.app.ActivityManagerNative;
 import android.app.AppOpsManager;
 import android.app.IActivityManager;
@@ -127,6 +57,7 @@
 import android.os.PowerManager;
 import android.os.PowerManagerInternal;
 import android.os.Process;
+import android.os.RemoteCallbackList;
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.StrictMode;
@@ -154,7 +85,7 @@
 import android.view.Gravity;
 import android.view.IAppTransitionAnimationSpecsFuture;
 import android.view.IApplicationToken;
-import android.view.IDockDividerVisibilityListener;
+import android.view.IDockedStackListener;
 import android.view.IInputFilter;
 import android.view.IOnKeyguardExitResult;
 import android.view.IRotationWatcher;
@@ -224,9 +155,83 @@
 import java.util.Iterator;
 import java.util.List;
 
+import static android.app.ActivityManager.DOCKED_STACK_CREATE_MODE_TOP_OR_LEFT;
+import static android.app.ActivityManager.StackId.DOCKED_STACK_ID;
+import static android.app.ActivityManager.StackId.FREEFORM_WORKSPACE_STACK_ID;
+import static android.app.StatusBarManager.DISABLE_MASK;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_BEHIND;
+import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
+import static android.view.WindowManager.DOCKED_INVALID;
+import static android.view.WindowManager.LayoutParams.FIRST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.FIRST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
+import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
+import static android.view.WindowManager.LayoutParams.FLAG_SECURE;
+import static android.view.WindowManager.LayoutParams.FLAG_SHOW_WALLPAPER;
+import static android.view.WindowManager.LayoutParams.INPUT_FEATURE_NO_INPUT_CHANNEL;
+import static android.view.WindowManager.LayoutParams.LAST_APPLICATION_WINDOW;
+import static android.view.WindowManager.LayoutParams.LAST_SUB_WINDOW;
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_COMPATIBLE_WINDOW;
+import static android.view.WindowManager.LayoutParams.TYPE_ACCESSIBILITY_OVERLAY;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_STARTING;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
+import static android.view.WindowManager.LayoutParams.TYPE_BOOT_PROGRESS;
+import static android.view.WindowManager.LayoutParams.TYPE_DOCK_DIVIDER;
+import static android.view.WindowManager.LayoutParams.TYPE_DREAM;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD;
+import static android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_PRIVATE_PRESENTATION;
+import static android.view.WindowManager.LayoutParams.TYPE_QS_DIALOG;
+import static android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR;
+import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
+import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
+import static android.view.WindowManagerGlobal.RELAYOUT_DEFER_SURFACE_DESTROY;
+import static android.view.WindowManagerGlobal.RELAYOUT_RES_SURFACE_CHANGED;
+import static android.view.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_END;
+import static com.android.server.wm.AppWindowAnimator.PROLONG_ANIMATION_AT_START;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ADD_REMOVE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ANIM;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_APP_TRANSITIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_BOOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_CONFIGURATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DISPLAY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_DRAG;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_KEYGUARD;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREENSHOT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SCREEN_ON;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STACK;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_STARTING_WINDOW;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TASK_POSITIONING;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_TOKEN_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_VISIBILITY;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WALLPAPER_LIGHT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_MOVEMENT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_WINDOW_TRACE;
+import static com.android.server.wm.WindowManagerDebugConfig.HIDE_STACK_CRAWLS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_SURFACE_ALLOC;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.SHOW_VERBOSE_TRANSACTIONS;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
+import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+
 /** {@hide} */
 public class WindowManagerService extends IWindowManager.Stub
         implements Watchdog.Monitor, WindowManagerPolicy.WindowManagerFuncs {
+    private static final String TAG = TAG_WITH_CLASS_NAME ? "WindowManagerService" : TAG_WM;
+
     static final int LAYOUT_REPEAT_THRESHOLD = 4;
 
     static final boolean PROFILE_ORIENTATION = false;
@@ -2426,13 +2431,17 @@
         }
     }
 
-    void setInsetsWindow(Session session, IWindow client,
-            int touchableInsets, Rect contentInsets,
+    void setInsetsWindow(Session session, IWindow client, int touchableInsets, Rect contentInsets,
             Rect visibleInsets, Region touchableRegion) {
         long origId = Binder.clearCallingIdentity();
         try {
             synchronized (mWindowMap) {
                 WindowState w = windowForClientLocked(session, client, false);
+                if (DEBUG_LAYOUT) Slog.d(TAG, "setInsetsWindow " + w
+                        + ", contentInsets=" + w.mGivenContentInsets + " -> " + contentInsets
+                        + ", visibleInsets=" + w.mGivenVisibleInsets + " -> " + visibleInsets
+                        + ", touchableRegion=" + w.mGivenTouchableRegion + " -> " + touchableRegion
+                        + ", touchableInsets " + w.mTouchableInsets + " -> " + touchableInsets);
                 if (w != null) {
                     w.mGivenInsetsPending = false;
                     w.mGivenContentInsets.set(contentInsets);
@@ -3203,7 +3212,8 @@
     public void addAppToken(int addPos, IApplicationToken token, int taskId, int stackId,
             int requestedOrientation, boolean fullscreen, boolean showForAllUsers, int userId,
             int configChanges, boolean voiceInteraction, boolean launchTaskBehind,
-            Rect taskBounds, Configuration config, boolean cropWindowsToStack) {
+            Rect taskBounds, Configuration config, boolean cropWindowsToStack,
+            boolean alwaysFocusable) {
         if (!checkCallingPermission(android.Manifest.permission.MANAGE_APP_TOKENS,
                 "addAppToken()")) {
             throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
@@ -3238,6 +3248,7 @@
                     (ActivityInfo.CONFIG_SCREEN_SIZE | ActivityInfo.CONFIG_ORIENTATION)) != 0;
             atoken.mLaunchTaskBehind = launchTaskBehind;
             atoken.mCropWindowsToStack = cropWindowsToStack;
+            atoken.mAlwaysFocusable = alwaysFocusable;
             if (DEBUG_TOKEN_MOVEMENT || DEBUG_ADD_REMOVE) Slog.v(TAG_WM, "addAppToken: " + atoken
                     + " to stack=" + stackId + " task=" + taskId + " at " + addPos);
 
@@ -4651,6 +4662,10 @@
                         if (DEBUG_STACK) Slog.d(TAG_WM, "attachStack: stackId=" + stackId);
                         stack = new TaskStack(this, stackId);
                         mStackIdToStack.put(stackId, stack);
+                        if (stackId == DOCKED_STACK_ID) {
+                            getDefaultDisplayContentLocked().mDividerControllerLocked
+                                    .notifyDockedStackExistsChanged(true);
+                        }
                     }
                     stack.attachDisplayContent(displayContent);
                     displayContent.attachStack(stack, onTop);
@@ -4676,6 +4691,10 @@
     void detachStackLocked(DisplayContent displayContent, TaskStack stack) {
         displayContent.detachStack(stack);
         stack.detachDisplay();
+        if (stack.mStackId == DOCKED_STACK_ID) {
+            getDefaultDisplayContentLocked().mDividerControllerLocked
+                    .notifyDockedStackExistsChanged(false);
+        }
     }
 
     public void detachStack(int stackId) {
@@ -4822,14 +4841,16 @@
      * @return True if the stack is now fullscreen.
      * */
     public boolean resizeStack(int stackId, Rect bounds,
-            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds) {
+            SparseArray<Configuration> configs, SparseArray<Rect> taskBounds,
+            SparseArray<Rect> taskTempInsetBounds) {
         synchronized (mWindowMap) {
             final TaskStack stack = mStackIdToStack.get(stackId);
             if (stack == null) {
                 throw new IllegalArgumentException("resizeStack: stackId " + stackId
                         + " not found.");
             }
-            if (stack.setBounds(bounds, configs, taskBounds) && stack.isVisibleLocked()) {
+            if (stack.setBounds(bounds, configs, taskBounds, taskTempInsetBounds)
+                    && stack.isVisibleLocked()) {
                 stack.resizeWindows();
                 stack.getDisplayContent().layoutNeeded = true;
                 mWindowPlacerLocked.performSurfacePlacement();
@@ -4838,6 +4859,17 @@
         }
     }
 
+    public void prepareFreezingTaskBounds(int stackId) {
+        synchronized (mWindowMap) {
+            final TaskStack stack = mStackIdToStack.get(stackId);
+            if (stack == null) {
+                throw new IllegalArgumentException("prepareFreezingTaskBounds: stackId " + stackId
+                        + " not found.");
+            }
+            stack.prepareFreezingTaskBounds();
+        }
+    }
+
     public void positionTaskInStack(int taskId, int stackId, int position, Rect bounds,
             Configuration config) {
         synchronized (mWindowMap) {
@@ -9078,8 +9110,8 @@
                         if (wtoken == token) {
                             break;
                         }
-                        if (mFocusedApp == token && token.stackCanReceiveKeys()) {
-                            // Whoops, we are below the focused app whose stack can receive keys...
+                        if (mFocusedApp == token && token.windowsAreFocusable()) {
+                            // Whoops, we are below the focused app whose windows are focusable...
                             // No focus for you!!!
                             if (localLOGV || DEBUG_FOCUS_LIGHT) Slog.v(TAG_WM,
                                     "findFocusedWindow: Reached focused app=" + mFocusedApp);
@@ -9464,6 +9496,32 @@
         }
     }
 
+    public void notifyAppRelaunching(IBinder token) {
+        synchronized (mWindowMap) {
+            AppWindowToken appWindow = findAppWindowToken(token);
+            if (canFreezeBounds(appWindow)) {
+                appWindow.freezeBounds();
+            }
+        }
+    }
+
+    public void notifyAppRelaunchingFinished(IBinder token) {
+        synchronized (mWindowMap) {
+            AppWindowToken appWindow = findAppWindowToken(token);
+            if (canFreezeBounds(appWindow)) {
+                appWindow.unfreezeBounds();
+            }
+        }
+    }
+
+    private boolean canFreezeBounds(AppWindowToken appWindow) {
+
+        // For freeform windows, we can't freeze the bounds at the moment because this would make
+        // the resizing unresponsive.
+        return appWindow != null && appWindow.mTask != null
+                && !appWindow.mTask.inFreeformWorkspace();
+    }
+
     void dumpPolicyLocked(PrintWriter pw, String[] args, boolean dumpAll) {
         pw.println("WINDOW MANAGER POLICY STATE (dumpsys window policy)");
         mPolicy.dump("    ", pw, args);
@@ -10128,7 +10186,8 @@
         synchronized (mWindowMap) {
             appWindowToken = findAppWindowToken(token);
             if (appWindowToken == null || !appWindowToken.isVisible()) {
-                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token " + token);
+                Slog.w(TAG_WM, "Attempted to set replacing window on non-existing app token "
+                        + token);
                 return;
             }
             appWindowToken.setReplacingWindows(animate);
@@ -10157,6 +10216,14 @@
         }
     }
 
+    @Override
+    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha) {
+        synchronized (mWindowMap) {
+            getDefaultDisplayContentLocked().getDockedDividerController().setResizeDimLayer(
+                    visible, targetStackId, alpha);
+        }
+    }
+
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (mWindowMap) {
             Task task = mTaskIdToTask.get(taskId);
@@ -10175,26 +10242,14 @@
     }
 
     @Override
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) {
         if (!checkCallingPermission(android.Manifest.permission.REGISTER_WINDOW_MANAGER_LISTENERS,
-                "registerDockDividerVisibilityListener()")) {
+                "registerDockedStackListener()")) {
             return;
         }
         // TODO(multi-display): The listener is registered on the default display only.
-        final DockedStackDividerController controller =
-                getDefaultDisplayContentLocked().getDockedDividerController();
-        controller.registerDockDividerVisibilityListener(listener);
-        try {
-            listener.asBinder().linkToDeath(new IBinder.DeathRecipient() {
-                @Override
-                public void binderDied() {
-                    getDefaultDisplayContentLocked().getDockedDividerController()
-                            .registerDockDividerVisibilityListener(null);
-                }
-            }, 0);
-        } catch (RemoteException e) {
-            controller.registerDockDividerVisibilityListener(null);
-        }
+        getDefaultDisplayContentLocked().mDividerControllerLocked.registerDockedStackListener(
+                listener);
     }
 
     private final class LocalService extends WindowManagerInternal {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 733bc29..6e4e01f 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -309,6 +309,12 @@
     // possible to draw.
     final Rect mOutsetFrame = new Rect();
 
+    /**
+     * Usually empty. Set to the task's tempInsetFrame. See
+     *{@link android.app.IActivityManager#resizeDockedStack}.
+     */
+    final Rect mInsetFrame = new Rect();
+
     boolean mContentChanged;
 
     // If a window showing a wallpaper: the requested offset for the
@@ -614,8 +620,18 @@
             // We use the parent frame as the containing frame for fullscreen and child windows
             mContainingFrame.set(pf);
             mDisplayFrame.set(df);
+            mInsetFrame.setEmpty();
         } else {
             task.getBounds(mContainingFrame);
+            task.getTempInsetBounds(mInsetFrame);
+            if (mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) {
+
+                // If the bounds are frozen, we still want to translate the window freely and only
+                // freeze the size.
+                Rect frozen = mAppToken.mFrozenBounds.peek();
+                mContainingFrame.right = mContainingFrame.left + frozen.width();
+                mContainingFrame.bottom = mContainingFrame.top + frozen.height();
+            }
             final WindowState imeWin = mService.mInputMethodWindow;
             if (imeWin != null && imeWin.isVisibleNow() && mService.mInputMethodTarget == this
                     && mContainingFrame.bottom > cf.bottom) {
@@ -674,6 +690,12 @@
             mOutsets.set(0, 0, 0, 0);
         }
 
+        // Denotes the actual frame used to calculate the insets. When resizing in docked mode,
+        // we'd like to freeze the layout, so we also need to freeze the insets temporarily. By the
+        // notion of a task having a different inset frame, we can achieve that while still moving
+        // the task around.
+        final Rect frame = !mInsetFrame.isEmpty() ? mInsetFrame : mFrame;
+
         // Make sure the content and visible frames are inside of the
         // final window frame.
         if (freeformWorkspace && !mFrame.isEmpty()) {
@@ -709,42 +731,69 @@
                 mContentFrame.set(mFrame);
             }
         } else {
-            mContentFrame.set(Math.max(mContentFrame.left, mFrame.left),
-                    Math.max(mContentFrame.top, mFrame.top),
-                    Math.min(mContentFrame.right, mFrame.right),
-                    Math.min(mContentFrame.bottom, mFrame.bottom));
+            mContentFrame.set(Math.max(mContentFrame.left, frame.left),
+                    Math.max(mContentFrame.top, frame.top),
+                    Math.min(mContentFrame.right, frame.right),
+                    Math.min(mContentFrame.bottom, frame.bottom));
 
-            mVisibleFrame.set(Math.max(mVisibleFrame.left, mFrame.left),
-                    Math.max(mVisibleFrame.top, mFrame.top),
-                    Math.min(mVisibleFrame.right, mFrame.right),
-                    Math.min(mVisibleFrame.bottom, mFrame.bottom));
+            mVisibleFrame.set(Math.max(mVisibleFrame.left, frame.left),
+                    Math.max(mVisibleFrame.top, frame.top),
+                    Math.min(mVisibleFrame.right, frame.right),
+                    Math.min(mVisibleFrame.bottom, frame.bottom));
 
-            mStableFrame.set(Math.max(mStableFrame.left, mFrame.left),
-                    Math.max(mStableFrame.top, mFrame.top),
-                    Math.min(mStableFrame.right, mFrame.right),
-                    Math.min(mStableFrame.bottom, mFrame.bottom));
+            mStableFrame.set(Math.max(mStableFrame.left, frame.left),
+                    Math.max(mStableFrame.top, frame.top),
+                    Math.min(mStableFrame.right, frame.right),
+                    Math.min(mStableFrame.bottom, frame.bottom));
         }
 
-        mOverscanInsets.set(Math.max(mOverscanFrame.left - mFrame.left, 0),
-                Math.max(mOverscanFrame.top - mFrame.top, 0),
-                Math.max(mFrame.right - mOverscanFrame.right, 0),
-                Math.max(mFrame.bottom - mOverscanFrame.bottom, 0));
+        mOverscanInsets.set(Math.max(mOverscanFrame.left - frame.left, 0),
+                Math.max(mOverscanFrame.top - frame.top, 0),
+                Math.max(frame.right - mOverscanFrame.right, 0),
+                Math.max(frame.bottom - mOverscanFrame.bottom, 0));
 
-        mContentInsets.set(mContentFrame.left - mFrame.left,
-                mContentFrame.top - mFrame.top,
-                mFrame.right - mContentFrame.right,
-                mFrame.bottom - mContentFrame.bottom);
+        mContentInsets.set(mContentFrame.left - frame.left,
+                mContentFrame.top - frame.top,
+                frame.right - mContentFrame.right,
+                frame.bottom - mContentFrame.bottom);
 
-        mVisibleInsets.set(mVisibleFrame.left - mFrame.left,
-                mVisibleFrame.top - mFrame.top,
-                mFrame.right - mVisibleFrame.right,
-                mFrame.bottom - mVisibleFrame.bottom);
+        mVisibleInsets.set(mVisibleFrame.left - frame.left,
+                mVisibleFrame.top - frame.top,
+                frame.right - mVisibleFrame.right,
+                frame.bottom - mVisibleFrame.bottom);
 
-        mStableInsets.set(Math.max(mStableFrame.left - mFrame.left, 0),
-                Math.max(mStableFrame.top - mFrame.top, 0),
-                Math.max(mFrame.right - mStableFrame.right, 0),
-                Math.max(mFrame.bottom - mStableFrame.bottom, 0));
+        if (mAttrs.type == TYPE_DOCK_DIVIDER) {
 
+            // For the docked divider, we calculate the stable insets like a full-screen window
+            // so it can use it to calculate the snap positions.
+            mStableInsets.set(Math.max(mStableFrame.left - mDisplayFrame.left, 0),
+                    Math.max(mStableFrame.top - mDisplayFrame.top, 0),
+                    Math.max(mDisplayFrame.right - mStableFrame.right, 0),
+                    Math.max(mDisplayFrame.bottom - mStableFrame.bottom, 0));
+        } else {
+            mStableInsets.set(Math.max(mStableFrame.left - frame.left, 0),
+                    Math.max(mStableFrame.top - frame.top, 0),
+                    Math.max(frame.right - mStableFrame.right, 0),
+                    Math.max(frame.bottom - mStableFrame.bottom, 0));
+        }
+
+        if (!mInsetFrame.isEmpty()) {
+            mContentFrame.set(mFrame);
+            mContentFrame.top += mContentInsets.top;
+            mContentFrame.bottom += mContentInsets.bottom;
+            mContentFrame.left += mContentInsets.left;
+            mContentFrame.right += mContentInsets.right;
+            mVisibleFrame.set(mFrame);
+            mVisibleFrame.top += mVisibleInsets.top;
+            mVisibleFrame.bottom += mVisibleInsets.bottom;
+            mVisibleFrame.left += mVisibleInsets.left;
+            mVisibleFrame.right += mVisibleInsets.right;
+            mStableFrame.set(mFrame);
+            mStableFrame.top += mStableInsets.top;
+            mStableFrame.bottom += mStableInsets.bottom;
+            mStableFrame.left += mStableInsets.left;
+            mStableFrame.right += mStableInsets.right;
+        }
         mCompatFrame.set(mFrame);
         if (mEnforceSizeCompat) {
             // If there is a size compatibility scale being applied to the
@@ -1558,12 +1607,7 @@
         return isVisibleOrAdding()
                 && (mViewVisibility == View.VISIBLE)
                 && ((mAttrs.flags & WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE) == 0)
-                && stackCanReceiveKeys();
-    }
-
-    boolean stackCanReceiveKeys() {
-        final TaskStack stack = getStack();
-        return stack != null && StackId.canReceiveKeys(stack.mStackId);
+                && (mAppToken == null || mAppToken.windowsAreFocusable());
     }
 
     @Override
@@ -1955,8 +1999,8 @@
         // isDragResizing() or isDragResizeChanged() is true.
         boolean resizing = isDragResizing() || isDragResizeChanged();
         final Rect backDropFrame = (inFreeformWorkspace() || !resizing) ? frame : mTmpRect;
-        mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets,
-                outsets, reportDraw, newConfig, backDropFrame);
+        mClient.resized(frame, overscanInsets, contentInsets, visibleInsets, stableInsets, outsets,
+                reportDraw, newConfig, backDropFrame);
     }
 
     public void registerFocusObserver(IWindowFocusObserver observer) {
@@ -2003,7 +2047,13 @@
         if (task.isDragResizing()) {
             return true;
         }
-        return mDisplayContent.mDividerControllerLocked.isResizing() &&
+
+        // If the bounds are currently frozen, it means that the layout size that the app sees
+        // and the bounds we clip this window to might be different. In order to avoid holes, we
+        // simulate that we are still resizing so the app fills the hole with the resizing
+        // background.
+        return (mDisplayContent.mDividerControllerLocked.isResizing()
+                        || mAppToken != null && !mAppToken.mFrozenBounds.isEmpty()) &&
                 !task.inFreeformWorkspace() && !task.isFullscreen();
     }
 
@@ -2302,10 +2352,15 @@
     }
 
     void setReplacing(boolean animate) {
-        if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) == 0) {
-            mWillReplaceWindow = true;
-            mReplacingWindow = null;
-            mAnimateReplacingWindow = animate;
+        if ((mAttrs.privateFlags & PRIVATE_FLAG_WILL_NOT_REPLACE_ON_RELAUNCH) != 0
+                || mAttrs.type == TYPE_APPLICATION_STARTING) {
+            // We don't set replacing on starting windows since they are added by window manager and
+            // not the client so won't be replaced by the client.
+            return;
         }
+
+        mWillReplaceWindow = true;
+        mReplacingWindow = null;
+        mAnimateReplacingWindow = animate;
     }
 }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 381db56..83ab190 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -37,6 +37,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerService.TYPE_LAYER_MULTIPLIER;
 import static com.android.server.wm.WindowManagerService.localLOGV;
+import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_DOCKED_DIVIDER;
 import static com.android.server.wm.WindowState.DRAG_RESIZE_MODE_FREEFORM;
 import static com.android.server.wm.WindowSurfacePlacer.SET_ORIENTATION_CHANGE_COMPLETE;
 import static com.android.server.wm.WindowSurfacePlacer.SET_TURN_ON_SCREEN;
@@ -1063,7 +1064,16 @@
         final int top = w.mYOffset + w.mFrame.top;
 
         // Initialize the decor rect to the entire frame.
-        mSystemDecorRect.set(0, 0, width, height);
+        if (w.isDragResizing() && w.getResizeMode() == DRAG_RESIZE_MODE_DOCKED_DIVIDER) {
+
+            // If we are resizing with the divider, the task bounds might be smaller than the
+            // stack bounds. The system decor is used to clip to the task bounds, which we don't
+            // want in this case in order to avoid holes.
+            final DisplayInfo displayInfo = w.getDisplayContent().getDisplayInfo();
+            mSystemDecorRect.set(0, 0, displayInfo.logicalWidth, displayInfo.logicalHeight);
+        } else {
+            mSystemDecorRect.set(0, 0, width, height);
+        }
 
         // If a freeform window is animating from a position where it would be cutoff, it would be
         // cutoff during the animation. We don't want that, so for the duration of the animation
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 6ebda07..feeab27 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -739,13 +739,15 @@
                             }
                         }
                     }
-                    /*
-                     * Updates the shown frame before we set up the surface. This is needed because
-                     * the resizing could change the top-left position (in addition to size) of the
-                     * window. setSurfaceBoundariesLocked uses mShownPosition to position the
-                      * surface.
-                     */
-                    winAnimator.computeShownFrameLocked();
+                    if (!winAnimator.isAnimating()) {
+                        // Updates the shown frame before we set up the surface. This is needed
+                        // because the resizing could change the top-left position (in addition to
+                        // size) of the window. setSurfaceBoundariesLocked uses mShownPosition to
+                        // position the surface. We only apply it to windows that aren't animating,
+                        // because we depend on the animation to calculate the correct shown frame
+                        // on the next animation step.
+                        winAnimator.computeShownFrameLocked();
+                    }
                     winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
                 }
 
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index cf661ce..7d1e66f 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -424,6 +424,8 @@
         private static final String TAG_PACKAGE_LIST_ITEM  = "item";
         private static final String TAG_KEEP_UNINSTALLED_PACKAGES  = "keep-uninstalled-packages";
         private static final String TAG_USER_RESTRICTIONS = "user-restrictions";
+        private static final String TAG_SHORT_SUPPORT_MESSAGE = "short-support-message";
+        private static final String TAG_LONG_SUPPORT_MESSAGE = "long-support-message";
 
         final DeviceAdminInfo info;
 
@@ -509,6 +511,10 @@
 
         Bundle userRestrictions;
 
+        // Support text provided by the admin to display to the user.
+        String shortSupportMessage = null;
+        String longSupportMessage = null;
+
         ActiveAdmin(DeviceAdminInfo _info) {
             info = _info;
         }
@@ -688,6 +694,16 @@
                 UserRestrictionsUtils.writeRestrictions(
                         out, userRestrictions, TAG_USER_RESTRICTIONS);
             }
+            if (!TextUtils.isEmpty(shortSupportMessage)) {
+                out.startTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+                out.text(shortSupportMessage);
+                out.endTag(null, TAG_SHORT_SUPPORT_MESSAGE);
+            }
+            if (!TextUtils.isEmpty(longSupportMessage)) {
+                out.startTag(null, TAG_LONG_SUPPORT_MESSAGE);
+                out.text(longSupportMessage);
+                out.endTag(null, TAG_LONG_SUPPORT_MESSAGE);
+            }
         }
 
         void writePackageListToXml(XmlSerializer out, String outerTag,
@@ -801,6 +817,20 @@
                     keepUninstalledPackages = readPackageList(parser, tag);
                 } else if (TAG_USER_RESTRICTIONS.equals(tag)) {
                     UserRestrictionsUtils.readRestrictions(parser, ensureUserRestrictions());
+                } else if (TAG_SHORT_SUPPORT_MESSAGE.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        shortSupportMessage = parser.getText();
+                    } else {
+                        Log.w(LOG_TAG, "Missing text when loading short support message");
+                    }
+                } else if (TAG_LONG_SUPPORT_MESSAGE.equals(tag)) {
+                    type = parser.next();
+                    if (type == XmlPullParser.TEXT) {
+                        longSupportMessage = parser.getText();
+                    } else {
+                        Log.w(LOG_TAG, "Missing text when loading long support message");
+                    }
                 } else {
                     Slog.w(LOG_TAG, "Unknown admin tag: " + tag);
                     XmlUtils.skipCurrentTag(parser);
@@ -1599,6 +1629,23 @@
         }
     }
 
+    /**
+     * Find the admin for the component and userId bit of the uid, then check
+     * the admin's uid matches the uid.
+     */
+    private ActiveAdmin getActiveAdminForUidLocked(ComponentName who, int uid) {
+        final int userId = UserHandle.getUserId(uid);
+        final DevicePolicyData policy = getUserData(userId);
+        ActiveAdmin admin = policy.mAdminMap.get(who);
+        if (admin == null) {
+            throw new SecurityException("No active admin " + who);
+        }
+        if (admin.getUid() != uid) {
+            throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
+        }
+        return admin;
+    }
+
     private ActiveAdmin getActiveAdminWithPolicyForUidLocked(ComponentName who, int reqPolicy,
             int uid) {
         // Try to find an admin which can use reqPolicy
@@ -1610,8 +1657,7 @@
                 throw new SecurityException("No active admin " + who);
             }
             if (admin.getUid() != uid) {
-                throw new SecurityException("Admin " + who + " is not owned by uid "
-                        + mInjector.binderGetCallingUid());
+                throw new SecurityException("Admin " + who + " is not owned by uid " + uid);
             }
             if (isActiveAdminWithPolicyForUserLocked(admin, reqPolicy, userId)) {
                 return admin;
@@ -7104,4 +7150,99 @@
         }
     }
 
+    @Override
+    public void setShortSupportMessage(@NonNull ComponentName who, String message) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            if (!TextUtils.equals(admin.shortSupportMessage, message)) {
+                admin.shortSupportMessage = message;
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
+
+    @Override
+    public String getShortSupportMessage(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            return admin.shortSupportMessage;
+        }
+    }
+
+    @Override
+    public void setLongSupportMessage(@NonNull ComponentName who, String message) {
+        if (!mHasFeature) {
+            return;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        final int userHandle = mInjector.userHandleGetCallingUserId();
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            if (!TextUtils.equals(admin.longSupportMessage, message)) {
+                admin.longSupportMessage = message;
+                saveSettingsLocked(userHandle);
+            }
+        }
+    }
+
+    @Override
+    public String getLongSupportMessage(@NonNull ComponentName who) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminForUidLocked(who,
+                    mInjector.binderGetCallingUid());
+            return admin.longSupportMessage;
+        }
+    }
+
+    @Override
+    public String getShortSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+            throw new SecurityException("Only the system can query support message for user");
+        }
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin != null) {
+                return admin.shortSupportMessage;
+            }
+        }
+        return null;
+    }
+
+    @Override
+    public String getLongSupportMessageForUser(@NonNull ComponentName who, int userHandle) {
+        if (!mHasFeature) {
+            return null;
+        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        if (!UserHandle.isSameApp(mInjector.binderGetCallingUid(), Process.SYSTEM_UID)) {
+            throw new SecurityException("Only the system can query support message for user");
+        }
+        synchronized (this) {
+            ActiveAdmin admin = getActiveAdminUncheckedLocked(who, userHandle);
+            if (admin != null) {
+                return admin.longSupportMessage;
+            }
+        }
+        return null;
+    }
 }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 0bbd23e..dd6493c 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1322,7 +1322,7 @@
         Intent intent = new Intent();
         intent.setComponent(new ComponentName("com.android.systemui",
                     "com.android.systemui.SystemUIService"));
-        intent.addFlags(Intent.FLAG_DEBUG_ENCRYPTION_TRIAGED);
+        intent.addFlags(Intent.FLAG_DEBUG_TRIAGED_MISSING);
         //Slog.d(TAG, "Starting service: " + intent);
         context.startServiceAsUser(intent, UserHandle.SYSTEM);
     }
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index 568e1d5..8270eef 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -1385,4 +1385,95 @@
 
         dpm.reboot(admin1);
     }
+
+    public void testSetGetSupportText() {
+        mContext.callerPermissions.add(permission.MANAGE_DEVICE_ADMINS);
+        dpm.setActiveAdmin(admin1, true);
+        dpm.setActiveAdmin(admin2, true);
+        mContext.callerPermissions.remove(permission.MANAGE_DEVICE_ADMINS);
+
+        // Null default support messages.
+        {
+            assertNull(dpm.getLongSupportMessage(admin1));
+            assertNull(dpm.getShortSupportMessage(admin1));
+            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+            assertNull(dpm.getShortSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getLongSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        }
+
+        // Only system can call the per user versions.
+        {
+            try {
+                dpm.getShortSupportMessageForUser(admin1,
+                        DpmMockContext.CALLER_USER_HANDLE);
+                fail("Only system should be able to call getXXXForUser versions");
+            } catch (SecurityException expected) {
+                MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+            }
+            try {
+                dpm.getLongSupportMessageForUser(admin1,
+                        DpmMockContext.CALLER_USER_HANDLE);
+                fail("Only system should be able to call getXXXForUser versions");
+            } catch (SecurityException expected) {
+                MoreAsserts.assertContainsRegex("message for user", expected.getMessage());
+            }
+        }
+
+        // Can't set message for admin in another uid.
+        {
+            mContext.binder.callingUid = DpmMockContext.CALLER_UID + 1;
+            try {
+                dpm.setShortSupportMessage(admin1, "Some text");
+                fail("Admins should only be able to change their own support text.");
+            } catch (SecurityException expected) {
+                MoreAsserts.assertContainsRegex("is not owned by uid", expected.getMessage());
+            }
+            mContext.binder.callingUid = DpmMockContext.CALLER_UID;
+        }
+
+        // Set/Get short returns what it sets and other admins text isn't changed.
+        {
+            final String supportText = "Some text to test with.";
+            dpm.setShortSupportMessage(admin1, supportText);
+            assertEquals(supportText, dpm.getShortSupportMessage(admin1));
+            assertNull(dpm.getLongSupportMessage(admin1));
+            assertNull(dpm.getShortSupportMessage(admin2));
+
+            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+            assertEquals(supportText, dpm.getShortSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getShortSupportMessageForUser(admin2,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getLongSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+            dpm.setShortSupportMessage(admin1, null);
+            assertNull(dpm.getShortSupportMessage(admin1));
+        }
+
+        // Set/Get long returns what it sets and other admins text isn't changed.
+        {
+            final String supportText = "Some text to test with.\nWith more text.";
+            dpm.setLongSupportMessage(admin1, supportText);
+            assertEquals(supportText, dpm.getLongSupportMessage(admin1));
+            assertNull(dpm.getShortSupportMessage(admin1));
+            assertNull(dpm.getLongSupportMessage(admin2));
+
+            mContext.binder.callingUid = DpmMockContext.SYSTEM_UID;
+            assertEquals(supportText, dpm.getLongSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getLongSupportMessageForUser(admin2,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            assertNull(dpm.getShortSupportMessageForUser(admin1,
+                    DpmMockContext.CALLER_USER_HANDLE));
+            mMockContext.binder.callingUid = DpmMockContext.CALLER_UID;
+
+            dpm.setLongSupportMessage(admin1, null);
+            assertNull(dpm.getLongSupportMessage(admin1));
+        }
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
index df7b412..2640889 100644
--- a/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/servicestests/src/com/android/server/notification/RankingHelperTest.java
@@ -35,7 +35,7 @@
 
 public class RankingHelperTest extends AndroidTestCase {
     @Mock NotificationUsageStats mUsageStats;
-    @Mock Handler handler;
+    @Mock RankingHandler handler;
 
     private Notification mNotiGroupGSortA;
     private Notification mNotiGroupGSortB;
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 5d5df95..aa95e1d 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -242,8 +242,13 @@
          */
         public static final int PROPERTY_HIGH_DEF_AUDIO = 0x00000010;
 
+        /**
+         * Whether the call is associated with the work profile.
+         */
+        public static final int PROPERTY_WORK_CALL = 0x00000020;
+
         //******************************************************************************************
-        // Next PROPERTY value: 0x00000020
+        // Next PROPERTY value: 0x00000040
         //******************************************************************************************
 
         private final Uri mHandle;
diff --git a/telecomm/java/android/telecom/DefaultDialerManager.java b/telecomm/java/android/telecom/DefaultDialerManager.java
index 27ee804..a915d37 100644
--- a/telecomm/java/android/telecom/DefaultDialerManager.java
+++ b/telecomm/java/android/telecom/DefaultDialerManager.java
@@ -155,8 +155,7 @@
 
         // Get the list of apps registered for the DIAL intent with empty scheme
         Intent intent = new Intent(Intent.ACTION_DIAL);
-        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent,
-                PackageManager.MATCH_ENCRYPTION_DEFAULT);
+        List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, 0);
 
         List<String> packageNames = new ArrayList<>();
 
@@ -209,7 +208,7 @@
 
         final List<String> result = new ArrayList<>();
         final List<ResolveInfo> resolveInfoList = context.getPackageManager()
-                .queryIntentActivities(intent, PackageManager.MATCH_ENCRYPTION_DEFAULT);
+                .queryIntentActivities(intent, 0);
         final int length = resolveInfoList.size();
         for (int i = 0; i < length; i++) {
             final ActivityInfo info = resolveInfoList.get(i).activityInfo;
diff --git a/telecomm/java/android/telecom/InCallService.java b/telecomm/java/android/telecom/InCallService.java
index 5087080..426b240 100644
--- a/telecomm/java/android/telecom/InCallService.java
+++ b/telecomm/java/android/telecom/InCallService.java
@@ -49,7 +49,7 @@
  * <pre>
  * {@code
  * <service android:name="your.package.YourInCallServiceImplementation"
- *          android:permission="android.permission.BIND_IN_CALL_SERVICE">
+ *          android:permission="android.permission.BIND_INCALL_SERVICE">
  *      <meta-data android:name="android.telecom.IN_CALL_SERVICE_UI" android:value="true" />
  *      <intent-filter>
  *          <action android:name="android.telecom.InCallService"/>
diff --git a/telephony/java/android/telephony/ServiceState.java b/telephony/java/android/telephony/ServiceState.java
index 8537f9c..c680999 100644
--- a/telephony/java/android/telephony/ServiceState.java
+++ b/telephony/java/android/telephony/ServiceState.java
@@ -153,6 +153,17 @@
      * @hide
      */
     public static final int RIL_RADIO_TECHNOLOGY_IWLAN = 18;
+
+    /** @hide */
+    public static final int RIL_RADIO_CDMA_TECHNOLOGY_BITMASK =
+            (1 << (RIL_RADIO_TECHNOLOGY_IS95A - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_IS95B - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_1xRTT - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_0 - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_A - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EVDO_B - 1))
+                    | (1 << (RIL_RADIO_TECHNOLOGY_EHRPD - 1));
+
     /**
      * Available registration states for GSM, UMTS and CDMA.
      */
@@ -1141,16 +1152,8 @@
     }
 
     /** @hide */
-    public static boolean hasCdma(int radioTechnologyBitmask) {
-        int cdmaBitmask = (RIL_RADIO_TECHNOLOGY_IS95A
-                | RIL_RADIO_TECHNOLOGY_IS95B
-                | RIL_RADIO_TECHNOLOGY_1xRTT
-                | RIL_RADIO_TECHNOLOGY_EVDO_0
-                | RIL_RADIO_TECHNOLOGY_EVDO_A
-                | RIL_RADIO_TECHNOLOGY_EVDO_B
-                | RIL_RADIO_TECHNOLOGY_EHRPD);
-
-        return ((radioTechnologyBitmask & cdmaBitmask) != 0);
+    public static boolean bearerBitmapHasCdma(int radioTechnologyBitmap) {
+        return (RIL_RADIO_CDMA_TECHNOLOGY_BITMASK & radioTechnologyBitmap) != 0;
     }
 
     /** @hide */
diff --git a/test-runner/src/android/test/mock/MockPackageManager.java b/test-runner/src/android/test/mock/MockPackageManager.java
index 2813df5..2cef1b3 100644
--- a/test-runner/src/android/test/mock/MockPackageManager.java
+++ b/test-runner/src/android/test/mock/MockPackageManager.java
@@ -34,7 +34,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -820,7 +819,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
         throw new UnsupportedOperationException();
     }
 
@@ -957,7 +956,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI,
             PackageInstallObserver observer, int flags, String installerPackageName,
-            Uri verificationURI, ManifestDigest manifestDigest,
+            Uri verificationURI,
             ContainerEncryptionParams encryptionParams) {
         throw new UnsupportedOperationException();
     }
diff --git a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
index 3c2659f..b78fd49 100644
--- a/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
+++ b/tests/permission/src/com/android/framework/permission/tests/WindowManagerPermissionTests.java
@@ -93,7 +93,7 @@
 
         try {
             mWm.addAppToken(0, null, 0, 0, 0, false, false, 0, 0, false, false, null,
-                    Configuration.EMPTY, false);
+                    Configuration.EMPTY, false, false);
             fail("IWindowManager.addAppToken did not throw SecurityException as"
                     + " expected");
         } catch (SecurityException e) {
diff --git a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
index 40437fa..01ee18b 100644
--- a/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
+++ b/tools/layoutlib/bridge/src/android/view/IWindowManagerImpl.java
@@ -76,7 +76,7 @@
     @Override
     public void addAppToken(int arg0, IApplicationToken arg1, int arg2, int arg3, int arg4,
             boolean arg5, boolean arg6, int arg7, int arg8, boolean arg9, boolean arg10,
-            Rect arg11, Configuration arg12, boolean arg13) throws RemoteException {
+            Rect arg11, Configuration arg12, boolean arg13, boolean arg14) throws RemoteException {
         // TODO Auto-generated method stub
     }
 
@@ -543,6 +543,11 @@
     }
 
     @Override
-    public void registerDockDividerVisibilityListener(IDockDividerVisibilityListener listener) {
+    public void registerDockedStackListener(IDockedStackListener listener) throws RemoteException {
+    }
+
+    @Override
+    public void setResizeDimLayer(boolean visible, int targetStackId, float alpha)
+            throws RemoteException {
     }
 }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
index 683c4aa..c8e3d03 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/Bridge.java
@@ -183,7 +183,7 @@
      */
     private static LayoutLog sCurrentLog = sDefaultLog;
 
-    private static final int LAST_SUPPORTED_FEATURE = Features.CHOREOGRAPHER;
+    private static final int LAST_SUPPORTED_FEATURE = Features.THEME_PREVIEW_NAVIGATION_BAR;
 
     @Override
     public int getApiLevel() {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
index a2fad13..3f9574f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgePackageManager.java
@@ -34,7 +34,6 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.IntentFilterVerificationInfo;
 import android.content.pm.KeySet;
-import android.content.pm.ManifestDigest;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageInstaller;
 import android.content.pm.PackageItemInfo;
@@ -522,7 +521,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, IPackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
     }
 
     @Override
@@ -544,7 +543,7 @@
     @Override
     public void installPackageWithVerification(Uri packageURI, PackageInstallObserver observer,
             int flags, String installerPackageName, Uri verificationURI,
-            ManifestDigest manifestDigest, ContainerEncryptionParams encryptionParams) {
+            ContainerEncryptionParams encryptionParams) {
     }
 
     @Override
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index 9c89bfe..dfbc69b 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -19,9 +19,6 @@
 import com.android.layoutlib.bridge.android.BridgeContext;
 import com.android.resources.Density;
 
-import android.content.Context;
-import android.content.pm.ApplicationInfo;
-import android.util.AttributeSet;
 import android.util.DisplayMetrics;
 import android.view.View;
 import android.widget.LinearLayout;
@@ -41,29 +38,18 @@
     private static final int WIDTH_DEFAULT = 36;
     private static final int WIDTH_SW360 = 40;
     private static final int WIDTH_SW600 = 48;
-    private static final String LAYOUT_XML = "/bars/navigation_bar.xml";
+    protected static final String LAYOUT_XML = "/bars/navigation_bar.xml";
     private static final String LAYOUT_600DP_XML = "/bars/navigation_bar600dp.xml";
 
-
-    /**
-     * Constructor to be used when creating the {@link NavigationBar} as a regular control.
-     * This is currently used by the theme editor.
-     */
-    @SuppressWarnings("unused")
-    public NavigationBar(Context context, AttributeSet attrs) {
-        this((BridgeContext) context,
-                Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
-                LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
-                ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
-                        View.LAYOUT_DIRECTION_RTL,
-                (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
-                0);
+    public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+      boolean rtlEnabled, int simulatedPlatformVersion) {
+        this(context, density, orientation, isRtl, rtlEnabled, simulatedPlatformVersion,
+          getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML);
     }
 
-    public NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
-            boolean rtlEnabled, int simulatedPlatformVersion) {
-        super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
-                "navigation_bar.xml", simulatedPlatformVersion);
+    protected NavigationBar(BridgeContext context, Density density, int orientation, boolean isRtl,
+      boolean rtlEnabled, int simulatedPlatformVersion, String layoutPath) {
+        super(context, orientation, layoutPath, "navigation_bar.xml", simulatedPlatformVersion);
 
         int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
         setBackgroundColor(color == 0 ? 0xFF000000 : color);
@@ -117,7 +103,7 @@
         view.setLayoutParams(layoutParams);
     }
 
-    private static int getSidePadding(float sw) {
+    protected int getSidePadding(float sw) {
         if (sw >= 400) {
             return PADDING_WIDTH_SW400;
         }
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
new file mode 100644
index 0000000..0435280
--- /dev/null
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/ThemePreviewNavigationBar.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.layoutlib.bridge.bars;
+
+import com.android.layoutlib.bridge.android.BridgeContext;
+import com.android.resources.Density;
+
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.util.AttributeSet;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * Navigation Bar for the Theme Editor preview.
+ *
+ * For small bars, it is identical to {@link NavigationBar}.
+ * But wide bars from {@link NavigationBar} are too wide for the Theme Editor preview.
+ * To solve that problem, {@link ThemePreviewNavigationBar} use the layout for small bars,
+ * and have no padding on the sides. That way, they have a similar look as the true ones,
+ * and they fit in the Theme Editor preview.
+ */
+public class ThemePreviewNavigationBar extends NavigationBar {
+    private static final int PADDING_WIDTH_SW600 = 0;
+
+    @SuppressWarnings("unused")
+    public ThemePreviewNavigationBar(Context context, AttributeSet attrs) {
+        super((BridgeContext) context,
+                Density.getEnum(((BridgeContext) context).getMetrics().densityDpi),
+                LinearLayout.HORIZONTAL, // In this mode, it doesn't need to be render vertically
+                ((BridgeContext) context).getConfiguration().getLayoutDirection() ==
+                        View.LAYOUT_DIRECTION_RTL,
+                (context.getApplicationInfo().flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0,
+                0, LAYOUT_XML);
+    }
+
+    @Override
+    protected int getSidePadding(float sw) {
+        if (sw >= 600) {
+            return PADDING_WIDTH_SW600;
+        }
+        return super.getSidePadding(sw);
+    }
+}