Merge "Merged many autofill session metrics into AUTOFILL_REQUEST:" into pi-dev
diff --git a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
index 37b7acf..8683ca1 100644
--- a/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
+++ b/cmds/requestsync/src/com/android/commands/requestsync/RequestSync.java
@@ -211,10 +211,10 @@
                 mExtras.putBoolean(key, Boolean.valueOf(value));
 
             } else if (opt.equals("-f") || opt.equals("--foreground")) {
-                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE;
+                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
 
             } else if (opt.equals("-F") || opt.equals("--top")) {
-                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
+                mExemptionFlag = ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
 
             } else {
                 System.err.println("Error: Unknown option: " + opt);
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index d278b55..4909690 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -2228,6 +2228,8 @@
 Landroid/graphics/FontFamily;->addFontFromAssetManager(Landroid/content/res/AssetManager;Ljava/lang/String;IZIII[Landroid/graphics/fonts/FontVariationAxis;)Z
 Landroid/graphics/FontFamily;->addFontFromBuffer(Ljava/nio/ByteBuffer;I[Landroid/graphics/fonts/FontVariationAxis;II)Z
 Landroid/graphics/FontFamily;->freeze()Z
+Landroid/graphics/FontFamily;->mNativePtr:J
+Landroid/graphics/FontListParser;->parse(Ljava/io/InputStream;)Landroid/text/FontConfig;
 Landroid/graphics/fonts/FontVariationAxis;->mStyleValue:F
 Landroid/graphics/fonts/FontVariationAxis;->mTag:I
 Landroid/graphics/GraphicBuffer;-><init>(IIIIJ)V
@@ -2374,6 +2376,7 @@
 Landroid/hardware/camera2/CameraCharacteristics;->LED_AVAILABLE_LEDS:Landroid/hardware/camera2/CameraCharacteristics$Key;
 Landroid/hardware/camera2/CameraCharacteristics;->LENS_INFO_SHADING_MAP_SIZE:Landroid/hardware/camera2/CameraCharacteristics$Key;
 Landroid/hardware/camera2/CameraCharacteristics;->LOGICAL_MULTI_CAMERA_PHYSICAL_IDS:Landroid/hardware/camera2/CameraCharacteristics$Key;
+Landroid/hardware/camera2/CameraCharacteristics;->mProperties:Landroid/hardware/camera2/impl/CameraMetadataNative;
 Landroid/hardware/camera2/CameraCharacteristics;->QUIRKS_USE_PARTIAL_RESULT:Landroid/hardware/camera2/CameraCharacteristics$Key;
 Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_CHARACTERISTICS_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key;
 Landroid/hardware/camera2/CameraCharacteristics;->REQUEST_AVAILABLE_PHYSICAL_CAMERA_REQUEST_KEYS:Landroid/hardware/camera2/CameraCharacteristics$Key;
@@ -2430,6 +2433,9 @@
 Landroid/hardware/camera2/CaptureResult;->TONEMAP_CURVE_RED:Landroid/hardware/camera2/CaptureResult$Key;
 Landroid/hardware/camera2/impl/CameraMetadataNative$Key;->getTag()I
 Landroid/hardware/camera2/impl/CameraMetadataNative;->mMetadataPtr:J
+Landroid/hardware/camera2/impl/CameraMetadataNative;->nativeGetTagFromKeyLocal(Ljava/lang/String;)I
+Landroid/hardware/camera2/impl/CameraMetadataNative;->nativeGetTypeFromTagLocal(I)I
+Landroid/hardware/camera2/impl/CameraMetadataNative;->nativeReadValues(I)[B
 Landroid/hardware/camera2/utils/SurfaceUtils;->getSurfaceSize(Landroid/view/Surface;)Landroid/util/Size;
 Landroid/hardware/camera2/utils/TypeReference;-><init>()V
 Landroid/hardware/camera2/utils/TypeReference;->createSpecializedTypeReference(Ljava/lang/reflect/Type;)Landroid/hardware/camera2/utils/TypeReference;
@@ -3777,6 +3783,7 @@
 Landroid/os/BatteryStats$Timer;-><init>()V
 Landroid/os/BatteryStats$Timer;->getTotalTimeLocked(JI)J
 Landroid/os/BatteryStats$Uid$Pkg$Serv;->getLaunches(I)I
+Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStarts(I)I
 Landroid/os/BatteryStats$Uid$Pkg$Serv;->getStartTime(JI)J
 Landroid/os/BatteryStats$Uid$Pkg;-><init>()V
 Landroid/os/BatteryStats$Uid$Pkg;->getServiceStats()Landroid/util/ArrayMap;
@@ -3811,12 +3818,20 @@
 Landroid/os/BatteryStats$Uid;->getWifiMulticastTime(JI)J
 Landroid/os/BatteryStats$Uid;->getWifiScanTime(JI)J
 Landroid/os/BatteryStats;-><init>()V
+Landroid/os/BatteryStats;->computeBatteryRealtime(JI)J
 Landroid/os/BatteryStats;->computeBatteryTimeRemaining(J)J
 Landroid/os/BatteryStats;->computeBatteryUptime(JI)J
 Landroid/os/BatteryStats;->computeChargeTimeRemaining(J)J
+Landroid/os/BatteryStats;->getBatteryUptime(J)J
+Landroid/os/BatteryStats;->getGlobalWifiRunningTime(JI)J
 Landroid/os/BatteryStats;->getMobileRadioActiveTime(JI)J
 Landroid/os/BatteryStats;->getNetworkActivityBytes(II)J
+Landroid/os/BatteryStats;->getPhoneOnTime(JI)J
+Landroid/os/BatteryStats;->getPhoneSignalStrengthTime(IJI)J
+Landroid/os/BatteryStats;->getScreenBrightnessTime(IJI)J
+Landroid/os/BatteryStats;->getScreenOnTime(JI)J
 Landroid/os/BatteryStats;->getUidStats()Landroid/util/SparseArray;
+Landroid/os/BatteryStats;->getWifiOnTime(JI)J
 Landroid/os/BatteryStats;->NUM_DATA_CONNECTION_TYPES:I
 Landroid/os/BatteryStats;->NUM_SCREEN_BRIGHTNESS_BINS:I
 Landroid/os/BatteryStats;->startIteratingHistoryLocked()Z
@@ -5276,6 +5291,7 @@
 Landroid/telephony/PhoneNumberUtils;->MIN_MATCH:I
 Landroid/telephony/PhoneNumberUtils;->ttsSpanAsPhoneNumber(Ljava/lang/CharSequence;)Ljava/lang/CharSequence;
 Landroid/telephony/PhoneStateListener;-><init>(Landroid/os/Looper;)V
+Landroid/telephony/PhoneStateListener;->callback:Lcom/android/internal/telephony/IPhoneStateListener;
 Landroid/telephony/PhoneStateListener;->LISTEN_PRECISE_CALL_STATE:I
 Landroid/telephony/PhoneStateListener;->mSubId:Ljava/lang/Integer;
 Landroid/telephony/PhoneStateListener;->onDataConnectionRealTimeInfoChanged(Landroid/telephony/DataConnectionRealTimeInfo;)V
@@ -5537,6 +5553,14 @@
 Landroid/text/DynamicLayout;->getNumberOfBlocks()I
 Landroid/text/DynamicLayout;->setIndexFirstChangedBlock(I)V
 Landroid/text/DynamicLayout;->sStaticLayout:Landroid/text/StaticLayout;
+Landroid/text/FontConfig$Family;->getFonts()[Landroid/text/FontConfig$Font;
+Landroid/text/FontConfig$Family;->getName()Ljava/lang/String;
+Landroid/text/FontConfig$Family;->getVariant()I
+Landroid/text/FontConfig$Font;->getAxes()[Landroid/graphics/fonts/FontVariationAxis;
+Landroid/text/FontConfig$Font;->getTtcIndex()I
+Landroid/text/FontConfig$Font;->getWeight()I
+Landroid/text/FontConfig$Font;->isItalic()Z
+Landroid/text/FontConfig;->getFamilies()[Landroid/text/FontConfig$Family;
 Landroid/text/format/DateFormat;->getTimeFormatString(Landroid/content/Context;)Ljava/lang/String;
 Landroid/text/format/DateFormat;->getTimeFormatString(Landroid/content/Context;I)Ljava/lang/String;
 Landroid/text/format/DateFormat;->hasDesignator(Ljava/lang/CharSequence;C)Z
@@ -7400,6 +7424,7 @@
 Lcom/android/internal/app/AlertController;->setMessage(Ljava/lang/CharSequence;)V
 Lcom/android/internal/app/AlertController;->setTitle(Ljava/lang/CharSequence;)V
 Lcom/android/internal/app/AlertController;->setView(Landroid/view/View;)V
+Lcom/android/internal/app/IAppOpsCallback$Stub;-><init>()V
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->checkOperation(IILjava/lang/String;)I
 Lcom/android/internal/app/IAppOpsService$Stub$Proxy;->setMode(IILjava/lang/String;I)V
@@ -8174,6 +8199,7 @@
 Lcom/android/internal/telephony/ISms$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISms;
 Lcom/android/internal/telephony/ISub$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Lcom/android/internal/telephony/ISub$Stub;->asInterface(Landroid/os/IBinder;)Lcom/android/internal/telephony/ISub;
+Lcom/android/internal/telephony/ISub;->getActiveSubIdList()[I
 Lcom/android/internal/telephony/ISub;->getDefaultDataSubId()I
 Lcom/android/internal/telephony/ISub;->getDefaultSubId()I
 Lcom/android/internal/telephony/ISub;->setDefaultDataSubId(I)V
@@ -8997,6 +9023,20 @@
 Lorg/apache/http/conn/ssl/SSLSocketFactory;->sslcontext:Ljavax/net/ssl/SSLContext;
 Lorg/ccil/cowan/tagsoup/AttributesImpl;->data:[Ljava/lang/String;
 Lorg/ccil/cowan/tagsoup/AttributesImpl;->length:I
+Lorg/ccil/cowan/tagsoup/ElementType;->theAtts:Lorg/ccil/cowan/tagsoup/AttributesImpl;
+Lorg/ccil/cowan/tagsoup/ElementType;->theFlags:I
+Lorg/ccil/cowan/tagsoup/ElementType;->theLocalName:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/ElementType;->theMemberOf:I
+Lorg/ccil/cowan/tagsoup/ElementType;->theModel:I
+Lorg/ccil/cowan/tagsoup/ElementType;->theName:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/ElementType;->theNamespace:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/ElementType;->theParent:Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/ElementType;->theSchema:Lorg/ccil/cowan/tagsoup/Schema;
+Lorg/ccil/cowan/tagsoup/Schema;->theElementTypes:Ljava/util/HashMap;
+Lorg/ccil/cowan/tagsoup/Schema;->theEntities:Ljava/util/HashMap;
+Lorg/ccil/cowan/tagsoup/Schema;->thePrefix:Ljava/lang/String;
+Lorg/ccil/cowan/tagsoup/Schema;->theRoot:Lorg/ccil/cowan/tagsoup/ElementType;
+Lorg/ccil/cowan/tagsoup/Schema;->theURI:Ljava/lang/String;
 Lorg/json/JSONArray;->values:Ljava/util/List;
 Lorg/json/JSONArray;->writeTo(Lorg/json/JSONStringer;)V
 Lorg/json/JSONObject;->append(Ljava/lang/String;Ljava/lang/Object;)Lorg/json/JSONObject;
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index 2d007ad..60e8a12 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -144,13 +144,6 @@
      * @param bitmap Source where to extract from.
      */
     public static WallpaperColors fromBitmap(@NonNull Bitmap bitmap) {
-        return fromBitmap(bitmap, false /* computeHints */);
-    }
-
-    /**
-     * @hide
-     */
-    public static WallpaperColors fromBitmap(@NonNull Bitmap bitmap, boolean computeHints) {
         if (bitmap == null) {
             throw new IllegalArgumentException("Bitmap can't be null");
         }
@@ -200,7 +193,7 @@
             }
         }
 
-        int hints = computeHints ? calculateDarkHints(bitmap) : 0;
+        int hints = calculateDarkHints(bitmap);
 
         if (shouldRecycle) {
             bitmap.recycle();
diff --git a/core/java/android/app/usage/UsageStatsManager.java b/core/java/android/app/usage/UsageStatsManager.java
index 1b07784..72d209a 100644
--- a/core/java/android/app/usage/UsageStatsManager.java
+++ b/core/java/android/app/usage/UsageStatsManager.java
@@ -184,7 +184,11 @@
     /** @hide */
     public static final int REASON_SUB_USAGE_SLICE_PINNED_PRIV  = 0x000A;
     /** @hide */
-    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000B;
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE = 0x000B;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE = 0x000C;
+    /** @hide */
+    public static final int REASON_SUB_USAGE_EXEMPTED_SYNC_START = 0x000D;
 
     /** @hide */
     public static final int REASON_SUB_PREDICTED_RESTORED       = 0x0001;
@@ -669,13 +673,19 @@
                         sb.append("-sa");
                         break;
                     case REASON_SUB_USAGE_SLICE_PINNED:
-                        sb.append("slp");
+                        sb.append("-lp");
                         break;
                     case REASON_SUB_USAGE_SLICE_PINNED_PRIV:
-                        sb.append("slpp");
+                        sb.append("-lv");
+                        break;
+                    case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE:
+                        sb.append("-en");
+                        break;
+                    case REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE:
+                        sb.append("-ed");
                         break;
                     case REASON_SUB_USAGE_EXEMPTED_SYNC_START:
-                        sb.append("es");
+                        sb.append("-es");
                         break;
                 }
                 break;
diff --git a/core/java/android/app/usage/UsageStatsManagerInternal.java b/core/java/android/app/usage/UsageStatsManagerInternal.java
index b8628a4..1a656ab 100644
--- a/core/java/android/app/usage/UsageStatsManagerInternal.java
+++ b/core/java/android/app/usage/UsageStatsManagerInternal.java
@@ -245,7 +245,15 @@
             int numDeferredJobs, long timeSinceLastJobRun);
 
     /**
-     * Report a sync that was scheduled by an active app is about to be executed.
+     * Report a sync is scheduled by a foreground app.
+     *
+     * @param packageName name of the package that owns the sync adapter.
+     * @param userId which user the app is associated with
+     */
+    public abstract void reportExemptedSyncScheduled(String packageName, @UserIdInt int userId);
+
+    /**
+     * Report a sync that was scheduled by a foreground app is about to be executed.
      *
      * @param packageName name of the package that owns the sync adapter.
      * @param userId which user the app is associated with
diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java
index f7908b6..32a6743 100644
--- a/core/java/android/content/ContentResolver.java
+++ b/core/java/android/content/ContentResolver.java
@@ -520,27 +520,36 @@
     public static final int SYNC_EXEMPTION_NONE = 0;
 
     /**
-     * When executing a sync with this exemption, we'll put the target app in the ACTIVE bucket
-     * for 10 minutes. This will allow the sync adapter to schedule/run further syncs and jobs.
+     * Exemption given to a sync request made by a foreground app (including
+     * PROCESS_STATE_IMPORTANT_FOREGROUND).
      *
-     * Note this will still *not* let RARE apps to run syncs, because they still won't get network
-     * connection.
+     * At the schedule time, we promote the sync adapter app for a higher bucket:
+     * - If the device is not dozing (so the sync will start right away)
+     *   promote to ACTIVE for 1 hour.
+     * - If the device is dozing (so the sync *won't* start right away),
+     * promote to WORKING_SET for 4 hours, so it'll get a higher chance to be started once the
+     * device comes out of doze.
+     * - When the sync actually starts, we promote the sync adapter app to ACTIVE for 10 minutes,
+     * so it can schedule and start more syncs without getting throttled, even when the first
+     * operation was canceled and now we're retrying.
+     *
+     *
      * @hide
      */
-    public static final int SYNC_EXEMPTION_ACTIVE = 1;
+    public static final int SYNC_EXEMPTION_PROMOTE_BUCKET = 1;
 
     /**
-     * In addition to {@link #SYNC_EXEMPTION_ACTIVE}, we put the sync adapter app in the
+     * In addition to {@link #SYNC_EXEMPTION_PROMOTE_BUCKET}, we put the sync adapter app in the
      * temp whitelist for 10 minutes, so that even RARE apps can run syncs right away.
      * @hide
      */
-    public static final int SYNC_EXEMPTION_ACTIVE_WITH_TEMP = 2;
+    public static final int SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP = 2;
 
     /** @hide */
     @IntDef(flag = false, prefix = { "SYNC_EXEMPTION_" }, value = {
             SYNC_EXEMPTION_NONE,
-            SYNC_EXEMPTION_ACTIVE,
-            SYNC_EXEMPTION_ACTIVE_WITH_TEMP,
+            SYNC_EXEMPTION_PROMOTE_BUCKET,
+            SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface SyncExemption {}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index c988fa9..03e600e 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -598,6 +598,8 @@
     boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId);
     boolean getApplicationHiddenSettingAsUser(String packageName, int userId);
 
+    boolean setSystemAppInstallState(String packageName, boolean installed, int userId);
+
     IPackageInstaller getPackageInstaller();
 
     boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index c3548e5..15aedd7 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -147,6 +147,7 @@
             GET_DISABLED_COMPONENTS,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
+            MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface PackageInfoFlags {}
@@ -164,6 +165,7 @@
             MATCH_STATIC_SHARED_LIBRARIES,
             GET_DISABLED_UNTIL_USED_COMPONENTS,
             GET_UNINSTALLED_PACKAGES,
+            MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS,
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface ApplicationInfoFlags {}
@@ -521,6 +523,12 @@
     public static final int MATCH_DEBUG_TRIAGED_MISSING = 0x10000000;
 
     /**
+     * Internal flag used to indicate that a package is a hidden system app.
+     * @hide
+     */
+    public static final int MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS =  0x20000000;
+
+    /**
      * Flag for {@link #addCrossProfileIntentFilter}: if this flag is set: when
      * resolving an intent that matches the {@code CrossProfileIntentFilter},
      * the current profile will be skipped. Only activities in the target user
@@ -4839,7 +4847,8 @@
      * on the system for other users, also install it for the specified user.
      * @hide
      */
-     @RequiresPermission(anyOf = {
+    @RequiresPermission(anyOf = {
+            Manifest.permission.INSTALL_EXISTING_PACKAGES,
             Manifest.permission.INSTALL_PACKAGES,
             Manifest.permission.INTERACT_ACROSS_USERS_FULL})
     public abstract int installExistingPackageAsUser(String packageName, @UserIdInt int userId)
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2da2cb4..b8eb074 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -639,11 +639,19 @@
      */
     private static boolean checkUseInstalledOrHidden(int flags, PackageUserState state,
             ApplicationInfo appInfo) {
+        // Returns false if the package is hidden system app until installed.
+        if ((flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) == 0
+                && !state.installed
+                && appInfo != null && appInfo.isSystemApp()) {
+            return false;
+        }
+
         // If available for the target user, or trying to match uninstalled packages and it's
         // a system app.
         return state.isAvailable(flags)
                 || (appInfo != null && appInfo.isSystemApp()
-                        && (flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0);
+                        && ((flags & PackageManager.MATCH_KNOWN_PACKAGES) != 0
+                        || (flags & PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS) != 0));
     }
 
     public static boolean isAvailable(PackageUserState state) {
diff --git a/core/java/android/hardware/camera2/CameraCharacteristics.java b/core/java/android/hardware/camera2/CameraCharacteristics.java
index 4279b19..87c64cd 100644
--- a/core/java/android/hardware/camera2/CameraCharacteristics.java
+++ b/core/java/android/hardware/camera2/CameraCharacteristics.java
@@ -81,6 +81,15 @@
          *
          * @hide
          */
+        public Key(String name, String fallbackName, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name,  fallbackName, type);
+        }
+
+        /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
         public Key(String name, Class<T> type) {
             mKey = new CameraMetadataNative.Key<T>(name,  type);
         }
diff --git a/core/java/android/hardware/camera2/CaptureResult.java b/core/java/android/hardware/camera2/CaptureResult.java
index c156616..6439338 100644
--- a/core/java/android/hardware/camera2/CaptureResult.java
+++ b/core/java/android/hardware/camera2/CaptureResult.java
@@ -87,6 +87,15 @@
          *
          * @hide
          */
+        public Key(String name, String fallbackName, Class<T> type) {
+            mKey = new CameraMetadataNative.Key<T>(name, fallbackName, type);
+        }
+
+       /**
+         * Visible for testing and vendor extensions only.
+         *
+         * @hide
+         */
         public Key(String name, Class<T> type) {
             mKey = new CameraMetadataNative.Key<T>(name, type);
         }
diff --git a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
index e4b1339..4baf263 100644
--- a/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
+++ b/core/java/android/hardware/camera2/impl/CameraMetadataNative.java
@@ -84,6 +84,7 @@
         private final Class<T> mType;
         private final TypeReference<T> mTypeReference;
         private final String mName;
+        private final String mFallbackName;
         private final int mHash;
 
         /**
@@ -96,6 +97,7 @@
                 throw new NullPointerException("Type needs to be non-null");
             }
             mName = name;
+            mFallbackName = null;
             mType = type;
             mVendorId = vendorId;
             mTypeReference = TypeReference.createSpecializedTypeReference(type);
@@ -103,6 +105,22 @@
         }
 
         /**
+         * @hide
+         */
+        public Key(String name, String fallbackName, Class<T> type) {
+            if (name == null) {
+                throw new NullPointerException("Key needs a valid name");
+            } else if (type == null) {
+                throw new NullPointerException("Type needs to be non-null");
+            }
+            mName = name;
+            mFallbackName = fallbackName;
+            mType = type;
+            mTypeReference = TypeReference.createSpecializedTypeReference(type);
+            mHash = mName.hashCode() ^ mTypeReference.hashCode();
+        }
+
+        /**
          * Visible for testing only.
          *
          * <p>Use the CameraCharacteristics.Key, CaptureResult.Key, or CaptureRequest.Key
@@ -115,6 +133,7 @@
                 throw new NullPointerException("Type needs to be non-null");
             }
             mName = name;
+            mFallbackName = null;
             mType = type;
             mTypeReference = TypeReference.createSpecializedTypeReference(type);
             mHash = mName.hashCode() ^ mTypeReference.hashCode();
@@ -134,6 +153,7 @@
                 throw new NullPointerException("TypeReference needs to be non-null");
             }
             mName = name;
+            mFallbackName = null;
             mType = (Class<T>)typeReference.getRawType();
             mTypeReference = typeReference;
             mHash = mName.hashCode() ^ mTypeReference.hashCode();
@@ -494,7 +514,16 @@
         int tag = nativeGetTagFromKeyLocal(key.getName());
         byte[] values = readValues(tag);
         if (values == null) {
-            return null;
+            // If the key returns null, use the fallback key if exists.
+            // This is to support old key names for the newly published keys.
+            if (key.mFallbackName == null) {
+                return null;
+            }
+            tag = nativeGetTagFromKeyLocal(key.mFallbackName);
+            values = readValues(tag);
+            if (values == null) {
+                return null;
+            }
         }
 
         int nativeType = nativeGetTypeFromTagLocal(tag);
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index b13f831..2d8b4d4 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -43,6 +43,7 @@
         DEFAULT_FLAGS.put("settings_bluetooth_while_driving", "false");
         DEFAULT_FLAGS.put("settings_data_usage_v2", "true");
         DEFAULT_FLAGS.put("settings_audio_switcher", "true");
+        DEFAULT_FLAGS.put("settings_systemui_theme", "false");
     }
 
     /**
diff --git a/core/java/android/view/textclassifier/TextClassificationManager.java b/core/java/android/view/textclassifier/TextClassificationManager.java
index aee0aa7..dc1194b 100644
--- a/core/java/android/view/textclassifier/TextClassificationManager.java
+++ b/core/java/android/view/textclassifier/TextClassificationManager.java
@@ -120,7 +120,7 @@
         synchronized (mLock) {
             if (mSettings == null) {
                 mSettings = TextClassificationConstants.loadFromString(Settings.Global.getString(
-                        mContext.getApplicationContext().getContentResolver(),
+                        getApplicationContext().getContentResolver(),
                         Settings.Global.TEXT_CLASSIFIER_CONSTANTS));
             }
             return mSettings;
@@ -186,8 +186,8 @@
     protected void finalize() throws Throwable {
         try {
             // Note that fields could be null if the constructor threw.
-            if (mContext != null && mSettingsObserver != null) {
-                mContext.getApplicationContext().getContentResolver()
+            if (mSettingsObserver != null) {
+                getApplicationContext().getContentResolver()
                         .unregisterContentObserver(mSettingsObserver);
             }
         } finally {
@@ -240,6 +240,12 @@
         }
     }
 
+    Context getApplicationContext() {
+        return mContext.getApplicationContext() != null
+                ? mContext.getApplicationContext()
+                : mContext;
+    }
+
     /** @hide */
     public static TextClassificationConstants getSettings(Context context) {
         Preconditions.checkNotNull(context);
@@ -261,7 +267,7 @@
         SettingsObserver(TextClassificationManager tcm) {
             super(null);
             mTcm = new WeakReference<>(tcm);
-            tcm.mContext.getApplicationContext().getContentResolver().registerContentObserver(
+            tcm.getApplicationContext().getContentResolver().registerContentObserver(
                     Settings.Global.getUriFor(Settings.Global.TEXT_CLASSIFIER_CONSTANTS),
                     false /* notifyForDescendants */,
                     this);
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index b49aace..a6b29c5 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -409,10 +409,9 @@
         }
         mBluetoothPowerCalculator.reset();
 
-        if (mSensorPowerCalculator == null) {
-            mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
-                    (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE));
-        }
+        mSensorPowerCalculator = new SensorPowerCalculator(mPowerProfile,
+                (SensorManager) mContext.getSystemService(Context.SENSOR_SERVICE),
+                mStats, rawRealtimeUs, statsType);
         mSensorPowerCalculator.reset();
 
         if (mCameraPowerCalculator == null) {
diff --git a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
index 8586d76..9e8f06d 100644
--- a/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
+++ b/core/java/com/android/internal/os/MobileRadioPowerCalculator.java
@@ -50,11 +50,33 @@
     }
 
     public MobileRadioPowerCalculator(PowerProfile profile, BatteryStats stats) {
-        mPowerRadioOn = profile.getAveragePower(PowerProfile.POWER_RADIO_ACTIVE);
-        for (int i = 0; i < mPowerBins.length; i++) {
-            mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
+        double temp =
+                profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ACTIVE, -1);
+        if (temp != -1) {
+            mPowerRadioOn = temp;
+        } else {
+            double sum = 0;
+            sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_RX);
+            for (int i = 0; i < mPowerBins.length; i++) {
+                sum += profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_TX, i);
+            }
+            mPowerRadioOn = sum / (mPowerBins.length + 1);
         }
-        mPowerScan = profile.getAveragePower(PowerProfile.POWER_RADIO_SCANNING);
+
+        temp = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_ON, -1);
+        if (temp != -1 ) {
+            for (int i = 0; i < mPowerBins.length; i++) {
+                mPowerBins[i] = profile.getAveragePower(PowerProfile.POWER_RADIO_ON, i);
+            }
+        } else {
+            double idle = profile.getAveragePower(PowerProfile.POWER_MODEM_CONTROLLER_IDLE);
+            mPowerBins[0] = idle * 25 / 180;
+            for (int i = 1; i < mPowerBins.length; i++) {
+                mPowerBins[i] = Math.max(1, idle / 256);
+            }
+        }
+
+        mPowerScan = profile.getAveragePowerOrDefault(PowerProfile.POWER_RADIO_SCANNING, 0);
         mStats = stats;
     }
 
diff --git a/core/java/com/android/internal/os/SensorPowerCalculator.java b/core/java/com/android/internal/os/SensorPowerCalculator.java
index c98639b..04cb49a 100644
--- a/core/java/com/android/internal/os/SensorPowerCalculator.java
+++ b/core/java/com/android/internal/os/SensorPowerCalculator.java
@@ -20,20 +20,23 @@
 import android.os.BatteryStats;
 import android.util.SparseArray;
 
+import com.android.internal.location.gnssmetrics.GnssMetrics;
+
 import java.util.List;
 
 public class SensorPowerCalculator extends PowerCalculator {
     private final List<Sensor> mSensors;
-    private final double mGpsPowerOn;
+    private final double mGpsPower;
 
-    public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager) {
+    public SensorPowerCalculator(PowerProfile profile, SensorManager sensorManager,
+            BatteryStats stats, long rawRealtimeUs, int statsType) {
         mSensors = sensorManager.getSensorList(Sensor.TYPE_ALL);
-        mGpsPowerOn = profile.getAveragePower(PowerProfile.POWER_GPS_ON);
+        mGpsPower = getAverageGpsPower(profile, stats, rawRealtimeUs, statsType);
     }
 
     @Override
     public void calculateApp(BatterySipper app, BatteryStats.Uid u, long rawRealtimeUs,
-                             long rawUptimeUs, int statsType) {
+            long rawUptimeUs, int statsType) {
         // Process Sensor usage
         final SparseArray<? extends BatteryStats.Uid.Sensor> sensorStats = u.getSensorStats();
         final int NSE = sensorStats.size();
@@ -42,10 +45,11 @@
             final int sensorHandle = sensorStats.keyAt(ise);
             final BatteryStats.Timer timer = sensor.getSensorTime();
             final long sensorTime = timer.getTotalTimeLocked(rawRealtimeUs, statsType) / 1000;
+
             switch (sensorHandle) {
                 case BatteryStats.Uid.Sensor.GPS:
                     app.gpsTimeMs = sensorTime;
-                    app.gpsPowerMah = (app.gpsTimeMs * mGpsPowerOn) / (1000*60*60);
+                    app.gpsPowerMah = (app.gpsTimeMs * mGpsPower) / (1000*60*60);
                     break;
                 default:
                     final int sensorsCount = mSensors.size();
@@ -60,4 +64,26 @@
             }
         }
     }
+
+    private double getAverageGpsPower(PowerProfile profile, BatteryStats stats, long rawRealtimeUs,
+            int statsType) {
+        double averagePower =
+                profile.getAveragePowerOrDefault(PowerProfile.POWER_GPS_ON, -1);
+        if (averagePower != -1) {
+            return averagePower;
+        }
+        averagePower = 0;
+        long totalTime = 0;
+        double totalPower = 0;
+        for (int i = 0; i < GnssMetrics.NUM_GPS_SIGNAL_QUALITY_LEVELS; i++) {
+            long timePerLevel = stats.getGpsSignalQualityTime(i, rawRealtimeUs, statsType);
+            totalTime += timePerLevel;
+            totalPower += profile.getAveragePower(PowerProfile.POWER_GPS_SIGNAL_QUALITY_BASED, i)
+                    * timePerLevel;
+        }
+        if (totalTime != 0) {
+            averagePower = totalPower / totalTime;
+        }
+        return averagePower;
+    }
 }
diff --git a/core/jni/android_hardware_camera2_DngCreator.cpp b/core/jni/android_hardware_camera2_DngCreator.cpp
index 567bb07..a794b7b 100644
--- a/core/jni/android_hardware_camera2_DngCreator.cpp
+++ b/core/jni/android_hardware_camera2_DngCreator.cpp
@@ -1770,20 +1770,79 @@
         status_t err = OK;
 
         // Set up rectilinear distortion correction
-        camera_metadata_entry entry3 =
-                results.find(ANDROID_LENS_RADIAL_DISTORTION);
+        float distortion[6] {1.f, 0.f, 0.f, 0.f, 0.f, 0.f};
+        bool gotDistortion = false;
+
         camera_metadata_entry entry4 =
                 results.find(ANDROID_LENS_INTRINSIC_CALIBRATION);
 
-        if (entry3.count == 6 && entry4.count == 5) {
+        if (entry4.count == 5) {
             float cx = entry4.data.f[/*c_x*/2];
             float cy = entry4.data.f[/*c_y*/3];
-            err = builder.addWarpRectilinearForMetadata(entry3.data.f, preWidth, preHeight, cx,
-                    cy);
-            if (err != OK) {
-                ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
-                jniThrowRuntimeException(env, "failed to add distortion correction.");
-                return nullptr;
+            // Assuming f_x = f_y, or at least close enough.
+            // Also assuming s = 0, or at least close enough.
+            float f = entry4.data.f[/*f_x*/0];
+
+            camera_metadata_entry entry3 =
+                    results.find(ANDROID_LENS_DISTORTION);
+            if (entry3.count == 5) {
+                gotDistortion = true;
+                float m_x = std::fmaxf(preWidth - cx, cx);
+                float m_y = std::fmaxf(preHeight - cy, cy);
+                float m_sq = m_x*m_x + m_y*m_y;
+                float m = sqrtf(m_sq); // distance to farthest corner from optical center
+                float f_sq = f * f;
+                // Conversion factors from Camera2 K factors for new LENS_DISTORTION field
+                // to DNG spec.
+                //
+                //       Camera2 / OpenCV assume distortion is applied in a space where focal length
+                //       is factored out, while DNG assumes a normalized space where the distance
+                //       from optical center to the farthest corner is 1.
+                //       Scale from camera2 to DNG spec accordingly.
+                //       distortion[0] is always 1 with the new LENS_DISTORTION field.
+                const double convCoeff[5] = {
+                    m_sq / f_sq,
+                    pow(m_sq, 2) / pow(f_sq, 2),
+                    pow(m_sq, 3) / pow(f_sq, 3),
+                    m / f,
+                    m / f
+                };
+                for (size_t i = 0; i < entry3.count; i++) {
+                    distortion[i+1] = convCoeff[i] * entry3.data.f[i];
+                }
+            } else {
+                entry3 = results.find(ANDROID_LENS_RADIAL_DISTORTION);
+                if (entry3.count == 6) {
+                    gotDistortion = true;
+                    // Conversion factors from Camera2 K factors to DNG spec. K factors:
+                    //
+                    //      Note: these are necessary because our unit system assumes a
+                    //      normalized max radius of sqrt(2), whereas the DNG spec's
+                    //      WarpRectilinear opcode assumes a normalized max radius of 1.
+                    //      Thus, each K coefficient must include the domain scaling
+                    //      factor (the DNG domain is scaled by sqrt(2) to emulate the
+                    //      domain used by the Camera2 specification).
+                    const double convCoeff[6] = {
+                        sqrt(2),
+                        2 * sqrt(2),
+                        4 * sqrt(2),
+                        8 * sqrt(2),
+                        2,
+                        2
+                    };
+                    for (size_t i = 0; i < entry3.count; i++) {
+                        distortion[i] = entry3.data.f[i] * convCoeff[i];
+                    }
+                }
+            }
+            if (gotDistortion) {
+                err = builder.addWarpRectilinearForMetadata(distortion, preWidth, preHeight, cx,
+                        cy);
+                if (err != OK) {
+                    ALOGE("%s: Could not add distortion correction.", __FUNCTION__);
+                    jniThrowRuntimeException(env, "failed to add distortion correction.");
+                    return nullptr;
+                }
             }
         }
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e35b631..19e5e21 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -3024,6 +3024,15 @@
     <permission android:name="android.permission.INSTALL_PACKAGE_UPDATES"
         android:protectionLevel="signature|privileged" />
 
+    <!-- Allows an application to install existing system packages. This is a limited
+         version of {@link android.Manifest.permission#INSTALL_PACKAGES}.
+         <p>Not for use by third-party applications.
+         TODO(b/80204953): remove this permission once we have a long-term solution.
+         @hide
+    -->
+    <permission android:name="com.android.permission.INSTALL_EXISTING_PACKAGES"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows an application to clear user data.
          <p>Not for use by third-party applications
          @hide
diff --git a/core/res/res/drawable/perm_group_camera.xml b/core/res/res/drawable/perm_group_camera.xml
index 61903a5..db7833f 100644
--- a/core/res/res/drawable/perm_group_camera.xml
+++ b/core/res/res/drawable/perm_group_camera.xml
@@ -22,10 +22,8 @@
 
     <path
         android:fillColor="#000000"
-        android:pathData="M 12 8.8 C 13.7673111995 8.8 15.2 10.2326888005 15.2 12 C 15.2 13.7673111995 13.7673111995 15.2 12 15.2 C 10.2326888005 15.2 8.8 13.7673111995 8.8 12 C 8.8 10.2326888005 10.2326888005 8.8 12 8.8 Z" />
+        android:pathData="M20,5h-3.17L15,3H9L7.17,5H4C2.9,5 2,5.9 2,7v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM20,19H4V7h16V19z"/>
     <path
         android:fillColor="#000000"
-        android:pathData="M9 2L7.17 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1 0 2-.9
-2-2V6c0-1.1-.9-2-2-2h-3.17L15 2H9zm3 15c-2.76 0-5-2.24-5-5s2.24-5 5-5 5 2.24 5
-5-2.24 5-5 5z" />
-</vector>
\ No newline at end of file
+        android:pathData="M12,9c-2.21,0 -4,1.79 -4,4c0,2.21 1.79,4 4,4s4,-1.79 4,-4C16,10.79 14.21,9 12,9z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_contacts.xml b/core/res/res/drawable/perm_group_contacts.xml
index 8f9dc3e..b834a27 100644
--- a/core/res/res/drawable/perm_group_contacts.xml
+++ b/core/res/res/drawable/perm_group_contacts.xml
@@ -22,8 +22,14 @@
 
     <path
         android:fillColor="#000000"
-        android:pathData="M20 0H4v2h16V0zM4 24h16v-2H4v2zM20 4H4c-1.1 0-2 .9-2 2v12c0 1.1 .9 2 2 2h16c1.1
-0 2-.9 2-2V6c0-1.1-.9-2-2-2zm-8 2.75c1.24 0 2.25 1.01 2.25 2.25s-1.01 2.25-2.25
-2.25S9.75 10.24 9.75 9 10.76 6.75 12 6.75zM17 17H7v-1.5c0-1.67 3.33-2.5 5-2.5s5
-.83 5 2.5V17z" />
-</vector>
\ No newline at end of file
+        android:pathData="M4,1h16v2h-16z"/>
+    <path
+        android:fillColor="#000000"
+        android:pathData="M4,21h16v2h-16z"/>
+    <path
+        android:fillColor="#000000"
+        android:pathData="M20,5H4C2.9,5 2,5.9 2,7v10c0,1.1 0.9,2 2,2h2h12h2c1.1,0 2,-0.9 2,-2V7C22,5.9 21.1,5 20,5zM8.21,17c0.7,-0.47 2.46,-1 3.79,-1s3.09,0.53 3.79,1H8.21zM20,17h-2c0,-1.99 -4,-3 -6,-3s-6,1.01 -6,3H4V7h16V17z"/>
+    <path
+        android:fillColor="#000000"
+        android:pathData="M12,13.5c1.66,0 3,-1.34 3,-3c0,-1.66 -1.34,-3 -3,-3s-3,1.34 -3,3C9,12.16 10.34,13.5 12,13.5zM12,9.5c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S11.45,9.5 12,9.5z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_location.xml b/core/res/res/drawable/perm_group_location.xml
index cc1ec90..a7fa524 100644
--- a/core/res/res/drawable/perm_group_location.xml
+++ b/core/res/res/drawable/perm_group_location.xml
@@ -22,6 +22,8 @@
 
     <path
         android:fillColor="#000000"
-        android:pathData="M12 2C8.13 2 5 5.13 5 9c0 5.25 7 13 7 13s7-7.75 7-13c0-3.87-3.13-7-7-7zm0
-9.5c-1.38 0-2.5-1.12-2.5-2.5s1.12-2.5 2.5-2.5 2.5 1.12 2.5 2.5-1.12 2.5-2.5 2.5z" />
-</vector>
\ No newline at end of file
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
+    <path
+        android:fillColor="#000000"
+        android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_microphone.xml b/core/res/res/drawable/perm_group_microphone.xml
index d494e67..9b532c1 100644
--- a/core/res/res/drawable/perm_group_microphone.xml
+++ b/core/res/res/drawable/perm_group_microphone.xml
@@ -22,7 +22,8 @@
 
     <path
         android:fillColor="#000000"
-        android:pathData="M12 14c1.66 0 2.99-1.34 2.99-3L15 5c0-1.66-1.34-3-3-3S9 3.34 9 5v6c0 1.66 1.34 3
-3 3zm5.3-3c0 3-2.54 5.1-5.3 5.1S6.7 14 6.7 11H5c0 3.41 2.72 6.23 6
-6.72V21h2v-3.28c3.28-.48 6-3.3 6-6.72h-1.7z" />
-</vector>
\ No newline at end of file
+        android:pathData="M12,14c1.66,0 3,-1.34 3,-3V5c0,-1.66 -1.34,-3 -3,-3S9,3.34 9,5v6C9,12.66 10.34,14 12,14zM11,5c0,-0.55 0.45,-1 1,-1s1,0.45 1,1v6c0,0.55 -0.45,1 -1,1s-1,-0.45 -1,-1V5z"/>
+    <path
+        android:fillColor="#000000"
+        android:pathData="M17,11c0,2.76 -2.24,5 -5,5s-5,-2.24 -5,-5H5c0,3.53 2.61,6.43 6,6.92V21h2v-3.08c3.39,-0.49 6,-3.39 6,-6.92H17z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_sms.xml b/core/res/res/drawable/perm_group_sms.xml
index 47bca19e..ebcf3d1 100644
--- a/core/res/res/drawable/perm_group_sms.xml
+++ b/core/res/res/drawable/perm_group_sms.xml
@@ -22,6 +22,5 @@
 
     <path
         android:fillColor="#000000"
-        android:pathData="M20 2H4c-1.1 0-1.99 .9 -1.99 2L2 22l4-4h14c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zM9
-11H7V9h2v2zm4 0h-2V9h2v2zm4 0h-2V9h2v2z" />
-</vector>
\ No newline at end of file
+        android:pathData="M20,2H4C2.9,2 2,2.9 2,4v18l4.75,-4h14C21.1,18 22,17.1 22,16V4C22,2.9 21.1,2 20,2zM20,16H4V4h16V16zM9,11H7V9h2V11zM17,11h-2V9h2V11zM13,11h-2V9h2V11z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_storage.xml b/core/res/res/drawable/perm_group_storage.xml
index 1ff1693..4b8965b 100644
--- a/core/res/res/drawable/perm_group_storage.xml
+++ b/core/res/res/drawable/perm_group_storage.xml
@@ -22,6 +22,5 @@
 
     <path
         android:fillColor="#000000"
-        android:pathData="M10 4H4c-1.1 0-1.99 .9 -1.99 2L2 18c0 1.1 .9 2 2 2h16c1.1 0 2-.9
-2-2V8c0-1.1-.9-2-2-2h-8l-2-2z" />
-</vector>
\ No newline at end of file
+        android:pathData="M20,6h-8l-2,-2H4C2.9,4 2.01,4.9 2.01,6L2,18c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2V8C22,6.9 21.1,6 20,6zM20,18H4V8h16V18z"/>
+</vector>
diff --git a/media/java/android/service/media/MediaBrowserService.java b/media/java/android/service/media/MediaBrowserService.java
index 6d1bd45..ca7ab7e 100644
--- a/media/java/android/service/media/MediaBrowserService.java
+++ b/media/java/android/service/media/MediaBrowserService.java
@@ -541,7 +541,8 @@
             throw new IllegalStateException("This should be called inside of onGetRoot or"
                     + " onLoadChildren or onLoadItem methods");
         }
-        return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid);
+        return new RemoteUserInfo(mCurConnection.pkg, mCurConnection.pid, mCurConnection.uid,
+                mCurConnection.callbacks.asBinder());
     }
 
     /**
diff --git a/media/jni/android_media_MediaCodec.cpp b/media/jni/android_media_MediaCodec.cpp
index 16f6284..3490ff8 100644
--- a/media/jni/android_media_MediaCodec.cpp
+++ b/media/jni/android_media_MediaCodec.cpp
@@ -742,7 +742,12 @@
 
 void JMediaCodec::setVideoScalingMode(int mode) {
     if (mSurfaceTextureClient != NULL) {
+        // this works for components that queue to surface
         native_window_set_scaling_mode(mSurfaceTextureClient.get(), mode);
+        // also signal via param for components that queue to IGBP
+        sp<AMessage> msg = new AMessage;
+        msg->setInt32("android._video-scaling", mode);
+        (void)mCodec->setParameters(msg);
     }
 }
 
diff --git a/media/jni/android_media_MediaPlayer.cpp b/media/jni/android_media_MediaPlayer.cpp
index eda22d5..5dd01b0 100644
--- a/media/jni/android_media_MediaPlayer.cpp
+++ b/media/jni/android_media_MediaPlayer.cpp
@@ -384,6 +384,9 @@
     process_media_player_call(
             env, thiz, mp->getBufferingSettings(&settings),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getBufferingSettings:{%s}", settings.toString().string());
 
     return bp.asJobject(env, gBufferingParamsFields);
@@ -555,6 +558,9 @@
     process_media_player_call(
             env, thiz, mp->getPlaybackSettings(&audioRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getPlaybackSettings: %f %f %d %d",
             audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
 
@@ -623,6 +629,9 @@
     process_media_player_call(
             env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
 
     ALOGV("getSyncSettings: %d %d %f %f",
             scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
diff --git a/media/jni/android_media_MediaPlayer2.cpp b/media/jni/android_media_MediaPlayer2.cpp
index 918a375..6546cf0 100644
--- a/media/jni/android_media_MediaPlayer2.cpp
+++ b/media/jni/android_media_MediaPlayer2.cpp
@@ -495,6 +495,9 @@
     process_media_player_call(
             env, thiz, mp->getBufferingSettings(&settings),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getBufferingSettings:{%s}", settings.toString().string());
 
     return bp.asJobject(env, gBufferingParamsFields);
@@ -662,6 +665,9 @@
     process_media_player_call(
             env, thiz, mp->getPlaybackSettings(&audioRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
     ALOGV("getPlaybackSettings: %f %f %d %d",
             audioRate.mSpeed, audioRate.mPitch, audioRate.mFallbackMode, audioRate.mStretchMode);
 
@@ -730,6 +736,9 @@
     process_media_player_call(
             env, thiz, mp->getSyncSettings(&scp.sync, &scp.frameRate),
             "java/lang/IllegalStateException", "unexpected error");
+    if (env->ExceptionCheck()) {
+        return nullptr;
+    }
 
     ALOGV("getSyncSettings: %d %d %f %f",
             scp.sync.mSource, scp.sync.mAudioAdjustMode, scp.sync.mTolerance, scp.frameRate);
diff --git a/packages/SettingsLib/res/drawable/ic_signal_location.xml b/packages/SettingsLib/res/drawable/ic_signal_location.xml
index 2f60580..1187093 100644
--- a/packages/SettingsLib/res/drawable/ic_signal_location.xml
+++ b/packages/SettingsLib/res/drawable/ic_signal_location.xml
@@ -19,11 +19,10 @@
     android:height="24dp"
     android:viewportWidth="24.0"
     android:viewportHeight="24.0">
-    <group
-        android:translateX="0.02"
-        android:translateY="0.82">
-        <path
-            android:pathData="M12,2C8.13,2 5,5.13 5,9c0,4.17 4.42,9.92 6.24,12.11 0.4,0.48 1.13,0.48 1.53,0C14.58,18.92 19,13.17 19,9c0,-3.87 -3.13,-7 -7,-7zM12,11.5a2.5,2.5 0,0 1,0 -5,2.5 2.5,0 0,1 0,5z"
-            android:fillColor="#FFFFFFFF"/>
-    </group>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
 </vector>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 85bbd59..fbe52d1 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -2935,7 +2935,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 167;
+            private static final int SETTINGS_VERSION = 168;
 
             private final int mUserId;
 
@@ -3792,6 +3792,19 @@
                     currentVersion = 167;
                 }
 
+                if (currentVersion == 167) {
+                    // Version 167: by default, vibrate for wireless charging
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    final Setting currentSetting = globalSettings.getSettingLocked(
+                            Global.CHARGING_VIBRATION_ENABLED);
+                    if (currentSetting.isNull()) {
+                        globalSettings.insertSettingLocked(
+                                Global.CHARGING_VIBRATION_ENABLED, "1",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 168;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/SystemUI/res/drawable/ic_ime_switcher_default.xml b/packages/SystemUI/res/drawable/ic_ime_switcher_default.xml
index 6a7f18b..d5f8a2a 100644
--- a/packages/SystemUI/res/drawable/ic_ime_switcher_default.xml
+++ b/packages/SystemUI/res/drawable/ic_ime_switcher_default.xml
@@ -15,11 +15,11 @@
   -->
 
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24.0dp"
-        android:height="24.0dp"
-        android:viewportWidth="24.0"
-        android:viewportHeight="24.0">
+        android:width="20dp"
+        android:height="20dp"
+        android:viewportWidth="24"
+        android:viewportHeight="24">
     <path
-        android:pathData="M21,4H3C1.9,4 1,4.9 1,6v13c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2V6C23,4.9 22.1,4 21,4zM21,19H3V6h18V19zM9,8h2v2H9V8zM5,8h2v2H5V8zM8,16h8v1H8V16zM13,8h2v2h-2V8zM9,12h2v2H9V12zM5,12h2v2H5V12zM13,12h2v2h-2V12zM17,8h2v2h-2V8zM17,12h2v2h-2V12z"
+        android:pathData="M19,7h2v2h-2V7zM15,7h2v2h-2V7zM3,7h2v2H3V7zM7,7h2v2H7V7zM11,7h2v2h-2V7zM19,11h2v2h-2V11zM15,11h2v2h-2V11zM3,11h2v2H3V11zM7,11h2v2H7V11zM11,11h2v2h-2V11zM7,15h10v2H7V15z"
         android:fillColor="?attr/singleToneColor"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
index 6fbc404..8d569b2 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
@@ -15,8 +15,8 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="24dp"
-    android:height="24dp"
+    android:width="21dp"
+    android:height="21dp"
     android:viewportWidth="24"
     android:viewportHeight="24">
     <path
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
index b02a252..93b2f9c8 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
@@ -19,10 +19,7 @@
     android:height="28dp"
     android:viewportWidth="28"
     android:viewportHeight="28">
-
     <path
-        android:fillColor="?attr/singleToneColor"
-        android:pathData="M17.25,10.15V14v3.85L14,15.95L10.69,14L14,12.05L17.25,10.15 M18.16,7.71c-0.14,0-0.28,0.04-0.42,0.12 l-4.63,2.72l-4.73,2.78c-0.52,0.3-0.52,1.05,0,1.36l4.73,2.78l4.63,2.72c0.13,0.08,0.28,0.12,0.42,0.12c0.44,0,0.84-0.36,0.84-0.86 V14V8.58C19,8.08,18.6,7.71,18.16,7.71L18.16,7.71z" />
-    <path
-        android:pathData="M 0 0 H 28 V 28 H 0 V 0 Z" />
+        android:pathData="M16.78,10.03l-3.97,3.97l3.97,3.97l-1.06,1.06l-5.03,-5.03l5.03,-5.03z"
+        android:fillColor="?attr/singleToneColor" />
 </vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_menu.xml b/packages/SystemUI/res/drawable/ic_sysbar_menu.xml
index 5cc1791..d53c95b 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_menu.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_menu.xml
@@ -15,8 +15,8 @@
      limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="28dp"
-    android:height="28dp"
+    android:width="21dp"
+    android:height="21dp"
     android:viewportWidth="28"
     android:viewportHeight="28">
 
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
index 6c1ae99..2cd7883 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_rotate_button.xml
@@ -17,14 +17,16 @@
 <animated-vector xmlns:android="http://schemas.android.com/apk/res/android" xmlns:aapt="http://schemas.android.com/aapt">
     <aapt:attr name="android:drawable">
         <vector android:name="root"
-                android:width="24dp"
-                android:height="24dp"
+                android:width="21dp"
+                android:height="21dp"
                 android:viewportWidth="24.0"
                 android:viewportHeight="24.0">
-            <group android:name="icon" android:pivotX="12" android:pivotY="12">
+            <!-- Use scaleX to flip icon so arrows always point in the direction of motion -->
+            <group android:name="icon" android:pivotX="12" android:pivotY="12"
+                   android:scaleX="?attr/rotateButtonScaleX">
                 <!-- Tint color to be set directly -->
                 <path android:fillColor="#FFFFFFFF"
-                    android:pathData="M17,1.01L7,1C5.9,1 5,1.9 5,3v18c0,1.1 0.9,2 2,2h10c1.1,0 2,-0.9 2,-2V3C19,1.9 18.1,1.01 17,1.01zM17,21H7l0,-1h10V21zM17,18H7V6h10V18zM7,4V3h10v1H7z"/>
+                      android:pathData="M19,12c0,1.72 -0.63,3.3 -1.66,4.52l-1.44,-1.44C16.58,14.23 17,13.17 17,12c0,-2.76 -2.24,-5 -5,-5c-0.06,0 -0.11,0.01 -0.17,0.01l1.08,1.08L11.5,9.5L8,6l3.5,-3.5l1.41,1.42l-1.09,1.09C11.88,5.01 11.94,5 12,5C15.87,5 19,8.13 19,12zM12.5,14.51l-1.41,1.41l1.06,1.06C12.1,16.99 12.05,17 12,17c-2.76,0 -5,-2.24 -5,-5c0,-1.17 0.42,-2.23 1.09,-3.08L6.66,7.48C5.62,8.7 5,10.28 5,12c0,3.87 3.13,7 7,7c0.06,0 0.13,-0.01 0.19,-0.01v0l-1.1,1.1l1.41,1.41L16,18L12.5,14.51z"/>
             </group>
         </vector>
     </aapt:attr>
diff --git a/packages/SystemUI/res/drawable/stat_sys_location.xml b/packages/SystemUI/res/drawable/stat_sys_location.xml
index 33ac5cd..bdb0b0c 100644
--- a/packages/SystemUI/res/drawable/stat_sys_location.xml
+++ b/packages/SystemUI/res/drawable/stat_sys_location.xml
@@ -19,11 +19,13 @@
         <vector
             android:width="17dp"
             android:height="17dp"
-            android:viewportWidth="48.0"
-            android:viewportHeight="48.0">
-
-        <path
-            android:fillColor="#FFFFFFFF"
-            android:pathData="M24.0,4.0c-7.7,0.0 -14.0,6.3 -14.0,14.0c0.0,10.5 14.0,26.0 14.0,26.0s14.0,-15.5 14.0,-26.0C38.0,10.3 31.7,4.0 24.0,4.0zM24.0,23.0c-2.8,0.0 -5.0,-2.2 -5.0,-5.0s2.2,-5.0 5.0,-5.0c2.8,0.0 5.0,2.2 5.0,5.0S26.8,23.0 24.0,23.0z"/>
+            android:viewportWidth="24.0"
+            android:viewportHeight="24.0">
+                <path
+                    android:fillColor="#FFFFFFFF"
+                    android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13C19,5.13 15.87,2 12,2zM7,9c0,-2.76 2.24,-5 5,-5s5,2.24 5,5c0,2.88 -2.88,7.19 -5,9.88C9.92,16.21 7,11.85 7,9z"/>
+                <path
+                    android:fillColor="#FFFFFFFF"
+                    android:pathData="M12,9m-2.5,0a2.5,2.5 0,1 1,5 0a2.5,2.5 0,1 1,-5 0"/>
         </vector>
 </inset>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/contextual.xml b/packages/SystemUI/res/layout/contextual.xml
new file mode 100644
index 0000000..94591e9
--- /dev/null
+++ b/packages/SystemUI/res/layout/contextual.xml
@@ -0,0 +1,72 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2018 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.
+-->
+
+<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+             xmlns:systemui="http://schemas.android.com/apk/res-auto"
+             android:id="@+id/menu_container"
+             android:layout_width="@dimen/navigation_key_width"
+             android:layout_height="match_parent"
+             android:importantForAccessibility="no"
+             android:clipChildren="false"
+             android:clipToPadding="false"
+             >
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/menu"
+        android:layout_height="match_parent"
+        android:layout_width="match_parent"
+        android:layout_weight="0"
+        android:scaleType="center"
+        systemui:keyCode="82"
+        systemui:playSound="false"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_menu"
+        android:paddingStart="@dimen/navigation_key_padding"
+        android:paddingEnd="@dimen/navigation_key_padding"
+    />
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/ime_switcher"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="0"
+        android:scaleType="center"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_ime_switch_button"
+        android:paddingStart="@dimen/navigation_key_padding"
+        android:paddingEnd="@dimen/navigation_key_padding"
+    />
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/rotate_suggestion"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="0"
+        android:scaleType="center"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_rotate_button"
+        android:paddingStart="@dimen/navigation_key_padding"
+        android:paddingEnd="@dimen/navigation_key_padding"
+    />
+    <com.android.systemui.statusbar.policy.KeyButtonView
+        android:id="@+id/accessibility_button"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_weight="0"
+        android:scaleType="center"
+        android:visibility="invisible"
+        android:contentDescription="@string/accessibility_accessibility_button"
+        android:paddingStart="@dimen/navigation_key_padding"
+        android:paddingEnd="@dimen/navigation_key_padding"
+    />
+</FrameLayout>
diff --git a/packages/SystemUI/res/layout/navigation_layout.xml b/packages/SystemUI/res/layout/navigation_layout.xml
index d72021e..baaf699 100644
--- a/packages/SystemUI/res/layout/navigation_layout.xml
+++ b/packages/SystemUI/res/layout/navigation_layout.xml
@@ -18,16 +18,14 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginStart="@dimen/rounded_corner_content_padding"
-    android:layout_marginEnd="@dimen/rounded_corner_content_padding"
-    android:paddingStart="@dimen/nav_content_padding"
-    android:paddingEnd="@dimen/nav_content_padding">
+    android:layout_height="match_parent">
 
     <com.android.systemui.statusbar.phone.NearestTouchFrame
         android:id="@+id/nav_buttons"
         android:layout_width="match_parent"
         android:layout_height="match_parent"
+        android:paddingStart="@dimen/rounded_corner_content_padding"
+        android:paddingEnd="@dimen/rounded_corner_content_padding"
         android:clipChildren="false"
         android:clipToPadding="false">
 
@@ -36,6 +34,8 @@
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="horizontal"
+            android:paddingStart="@dimen/nav_content_padding"
+            android:paddingEnd="@dimen/nav_content_padding"
             android:clipToPadding="false"
             android:clipChildren="false" />
 
@@ -46,6 +46,8 @@
             android:layout_gravity="center"
             android:gravity="center"
             android:orientation="horizontal"
+            android:paddingStart="@dimen/nav_content_padding"
+            android:paddingEnd="@dimen/nav_content_padding"
             android:clipToPadding="false"
             android:clipChildren="false" />
 
diff --git a/packages/SystemUI/res/layout/navigation_layout_rot90.xml b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
index 0e17e5b5..6d5b7788 100644
--- a/packages/SystemUI/res/layout/navigation_layout_rot90.xml
+++ b/packages/SystemUI/res/layout/navigation_layout_rot90.xml
@@ -18,23 +18,26 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:systemui="http://schemas.android.com/apk/res-auto"
     android:layout_width="match_parent"
-    android:layout_height="match_parent"
-    android:layout_marginTop="@dimen/rounded_corner_content_padding"
-    android:layout_marginBottom="@dimen/rounded_corner_content_padding"
-    android:paddingTop="8dp"
-    android:paddingBottom="8dp">
+    android:layout_height="match_parent">
 
     <com.android.systemui.statusbar.phone.NearestTouchFrame
         android:id="@+id/nav_buttons"
         android:layout_width="match_parent"
-        android:layout_height="match_parent">
+        android:layout_height="match_parent"
+        android:paddingTop="@dimen/rounded_corner_content_padding"
+        android:paddingBottom="@dimen/rounded_corner_content_padding"
+        android:clipChildren="false"
+        android:clipToPadding="false">
 
         <com.android.systemui.statusbar.phone.ReverseLinearLayout
             android:id="@+id/ends_group"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:orientation="vertical"
-            android:clipChildren="false" />
+            android:paddingTop="@dimen/nav_content_padding"
+            android:paddingBottom="@dimen/nav_content_padding"
+            android:clipChildren="false"
+            android:clipToPadding="false" />
 
         <com.android.systemui.statusbar.phone.ReverseLinearLayout
             android:id="@+id/center_group"
@@ -42,7 +45,10 @@
             android:layout_height="match_parent"
             android:gravity="center"
             android:orientation="vertical"
-            android:clipChildren="false" />
+            android:paddingTop="@dimen/nav_content_padding"
+            android:paddingBottom="@dimen/nav_content_padding"
+            android:clipChildren="false"
+            android:clipToPadding="false" />
 
     </com.android.systemui.statusbar.phone.NearestTouchFrame>
 
diff --git a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
index 7931dfe..8b56b68 100644
--- a/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
+++ b/packages/SystemUI/res/layout/status_bar_mobile_signal_group.xml
@@ -29,7 +29,6 @@
         android:layout_width="wrap_content"
         android:layout_height="match_parent"
         android:gravity="center_vertical"
-        android:paddingStart="2dp"
         android:orientation="horizontal" >
 
         <FrameLayout
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index 2ce9bfc..3f63f22 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -141,5 +141,7 @@
     <!-- Used to style rotate suggestion button AVD animations -->
     <attr name="rotateButtonStartAngle" format="float" />
     <attr name="rotateButtonEndAngle" format="float" />
+    <attr name="rotateButtonScaleX" format="float" />
+
 </resources>
 
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 251589b..a68ba9b 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -364,6 +364,7 @@
 
     <!-- Nav bar button default ordering/layout -->
     <string name="config_navBarLayout" translatable="false">left[.5W],back[1WC];home;recent[1WC],right[.5W]</string>
+    <string name="config_navBarLayoutQuickstep" translatable="false">back[1.7WC];home;contextual[1.7WC]</string>
 
     <bool name="quick_settings_show_full_alarm">false</bool>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 0024fe4..1aee7bc 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -201,7 +201,7 @@
     <dimen name="status_bar_padding_start">6dp</dimen>
 
     <!-- the padding on the end of the statusbar -->
-    <dimen name="status_bar_padding_end">8dp</dimen>
+    <dimen name="status_bar_padding_end">6dp</dimen>
 
     <!-- the radius of the overflow dot in the status bar -->
     <dimen name="overflow_dot_radius">1dp</dimen>
@@ -938,7 +938,7 @@
     <dimen name="rounded_corner_radius_bottom">0dp</dimen>
     <dimen name="rounded_corner_content_padding">0dp</dimen>
     <dimen name="nav_content_padding">0dp</dimen>
-    <dimen name="nav_quick_scrub_track_edge_padding">42dp</dimen>
+    <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
     <dimen name="nav_quick_scrub_track_thickness">2dp</dimen>
 
     <!-- Navigation bar shadow params. -->
@@ -1007,4 +1007,7 @@
     <dimen name="logout_button_margin_bottom">12dp</dimen>
     <dimen name="logout_button_corner_radius">2dp</dimen>
 
+    <!-- How much into a DisplayCutout's bounds we can go, on each side -->
+    <dimen name="display_cutout_margin_consumption">0px</dimen>
+
 </resources>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index b3f4534..e4f5989 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -506,21 +506,25 @@
     <style name="RotateButtonCCWStart0">
         <item name="rotateButtonStartAngle">0</item>
         <item name="rotateButtonEndAngle">-90</item>
+        <item name="rotateButtonScaleX">1</item>
     </style>
 
     <style name="RotateButtonCCWStart90">
         <item name="rotateButtonStartAngle">90</item>
         <item name="rotateButtonEndAngle">0</item>
+        <item name="rotateButtonScaleX">1</item>
     </style>
 
     <style name="RotateButtonCWStart0">
         <item name="rotateButtonStartAngle">0</item>
         <item name="rotateButtonEndAngle">90</item>
+        <item name="rotateButtonScaleX">-1</item>
     </style>
 
     <style name="RotateButtonCWStart90">
         <item name="rotateButtonStartAngle">90</item>
         <item name="rotateButtonEndAngle">180</item>
+        <item name="rotateButtonScaleX">-1</item>
     </style>
 
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
index 96ec232..cd831d1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/NavigationBarCompat.java
@@ -37,16 +37,12 @@
         return convertDpToPixel(10);
     }
 
-    public static int getQuickScrubDragSlopPx() {
-        return convertDpToPixel(20);
-    }
-
     public static int getQuickStepTouchSlopPx() {
         return convertDpToPixel(24);
     }
 
     public static int getQuickScrubTouchSlopPx() {
-        return convertDpToPixel(35);
+        return convertDpToPixel(24);
     }
 
     @Retention(RetentionPolicy.SOURCE)
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 2746a71..e347a14 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -196,6 +196,9 @@
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
         updateOrientation();
+        if (shouldDrawCutout() && mOverlay == null) {
+            setupDecorations();
+        }
     }
 
     protected void updateOrientation() {
@@ -207,10 +210,6 @@
                 updateLayoutParams();
                 updateViews();
             }
-
-            if (shouldDrawCutout() && mOverlay == null) {
-                setupDecorations();
-            }
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index bcc33d2..086c87b 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
@@ -48,7 +48,6 @@
 import android.os.SystemProperties;
 import android.os.UserManager;
 import android.os.RemoteException;
-import android.util.Log;
 import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.LayoutInflater;
@@ -163,8 +162,8 @@
                         if (mHasDismissedSwipeUpTip) {
                             int hasDimissedSwipeUpOnboardingCount =
                                     getDismissedSwipeUpOnboardingCount();
-                            if (hasDimissedSwipeUpOnboardingCount > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) {
-                                Log.d(TAG, "Should not be reached");
+                            if (hasDimissedSwipeUpOnboardingCount
+                                    > MAX_DISMISSAL_ON_SWIPE_UP_SHOW) {
                                 return;
                             }
                             final int swipeUpShowOnAppLauncherAfterDismiss =
@@ -174,7 +173,7 @@
                                             : SWIPE_UP_SHOW_ON_APP_LAUNCH_AFTER_DISMISS_BACK_OFF;
                             mNumAppsLaunchedSinceSwipeUpTipDismiss++;
                             if (mNumAppsLaunchedSinceSwipeUpTipDismiss
-                                    == swipeUpShowOnAppLauncherAfterDismiss) {
+                                    >= swipeUpShowOnAppLauncherAfterDismiss) {
                                 mNumAppsLaunchedSinceSwipeUpTipDismiss = 0;
                                 shouldLog = show(R.string.recents_swipe_up_onboarding);
                             }
@@ -189,7 +188,7 @@
                     if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
                         if (mHasDismissedQuickScrubTip) {
                             if (mOverviewOpenedCountSinceQuickScrubTipDismiss
-                                    == QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
+                                    >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
                                 mOverviewOpenedCountSinceQuickScrubTipDismiss = 0;
                                 shouldLog = show(R.string.recents_quick_scrub_onboarding);
                             }
@@ -216,9 +215,9 @@
                         setHasSeenSwipeUpOnboarding(true);
                     }
                     if (fromHome) {
-                        setOpenedOverviewFromHomeCount(getOpenedOverviewFromHomeCount() + 1);
+                        incrementOpenedOverviewFromHomeCount();
                     }
-                    setOpenedOverviewCount(getOpenedOverviewCount() + 1);
+                    incrementOpenedOverviewCount();
 
                     if (getOpenedOverviewCount() >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
                         if (mHasDismissedQuickScrubTip) {
@@ -245,15 +244,12 @@
             = new View.OnAttachStateChangeListener() {
         @Override
         public void onViewAttachedToWindow(View view) {
-            Log.d(TAG, "View attached");
             if (view == mLayout) {
                 mContext.registerReceiver(mReceiver, new IntentFilter(Intent.ACTION_SCREEN_OFF));
                 mLayoutAttachedToWindow = true;
                 if (view.getTag().equals(R.string.recents_swipe_up_onboarding)) {
-                    Log.d(TAG, "recents_swipe_up_onboarding tip attached");
                     mHasDismissedSwipeUpTip = false;
                 } else {
-                    Log.d(TAG, "recents_quick_scrub_onboarding tip attached");
                     mHasDismissedQuickScrubTip = false;
                 }
             }
@@ -261,11 +257,9 @@
 
         @Override
         public void onViewDetachedFromWindow(View view) {
-            Log.d(TAG, "View detached");
             if (view == mLayout) {
                 mLayoutAttachedToWindow = false;
                 if (view.getTag().equals(R.string.recents_quick_scrub_onboarding)) {
-                    Log.d(TAG, "recents_quick_scrub_onboarding tip detached");
                     mHasDismissedQuickScrubTip = true;
                     if (hasDismissedQuickScrubOnboardingOnce()) {
                         // If user dismisses the quick scrub tip twice, we consider user has seen it
@@ -353,29 +347,23 @@
             return;
         }
 
-        Log.d(TAG, "Connecting to launcher");
         if (!mOverviewProxyListenerRegistered) {
-            Log.d(TAG, "Registering mOverviewProxyListener");
             mOverviewProxyService.addCallback(mOverviewProxyListener);
             mOverviewProxyListenerRegistered = true;
         }
         if (!mTaskListenerRegistered) {
-            Log.d(TAG, "Registering mTaskListener");
             ActivityManagerWrapper.getInstance().registerTaskStackListener(mTaskListener);
             mTaskListenerRegistered = true;
         }
     }
 
     public void onDisconnectedFromLauncher() {
-        Log.d(TAG, "Disconnecting to launcher");
 
         if (mOverviewProxyListenerRegistered) {
-            Log.d(TAG, "Unregistering mOverviewProxyListener");
             mOverviewProxyService.removeCallback(mOverviewProxyListener);
             mOverviewProxyListenerRegistered = false;
         }
         if (mTaskListenerRegistered) {
-            Log.d(TAG, "Unregistering mTaskListener");
             ActivityManagerWrapper.getInstance().unregisterTaskStackListener(mTaskListener);
             mTaskListenerRegistered = false;
         }
@@ -403,8 +391,6 @@
         // Only show in portrait.
         int orientation = mContext.getResources().getConfiguration().orientation;
         if (!mLayoutAttachedToWindow && orientation == Configuration.ORIENTATION_PORTRAIT) {
-            Log.d(TAG, "Show " + (stringRes == R.string.recents_swipe_up_onboarding
-                    ? "recents_swipe_up_onboarding" : "recents_quick_scrub_onboarding") + " tip");
             mLayout.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
 
             mWindowManager.addView(mLayout, getWindowLayoutParams());
@@ -433,7 +419,6 @@
 
     public void hide(boolean animate) {
         if (mLayoutAttachedToWindow) {
-            Log.d(TAG, "Hide tip, animated: " + animate);
             if (animate) {
                 mLayout.animate()
                         .alpha(0f)
@@ -495,7 +480,6 @@
     }
 
     private void setHasSeenSwipeUpOnboarding(boolean hasSeenSwipeUpOnboarding) {
-        Log.d(TAG, "setHasSeenSwipeUpOnboarding: " + hasSeenSwipeUpOnboarding);
         Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_SWIPE_UP_ONBOARDING, hasSeenSwipeUpOnboarding);
         if (hasSeenSwipeUpOnboarding && hasSeenQuickScrubOnboarding()) {
             onDisconnectedFromLauncher();
@@ -507,7 +491,6 @@
     }
 
     private void setHasSeenQuickScrubOnboarding(boolean hasSeenQuickScrubOnboarding) {
-        Log.d(TAG, "setHasSeenQuickScrubOnboarding: " + hasSeenQuickScrubOnboarding);
         Prefs.putBoolean(mContext, HAS_SEEN_RECENTS_QUICK_SCRUB_ONBOARDING,
                 hasSeenQuickScrubOnboarding);
         if (hasSeenQuickScrubOnboarding && hasSeenSwipeUpOnboarding()) {
@@ -520,7 +503,6 @@
     }
 
     private void setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount) {
-        Log.d(TAG, "setDismissedSwipeUpOnboardingCount: " + dismissedSwipeUpOnboardingCount);
         Prefs.putInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT,
                 dismissedSwipeUpOnboardingCount);
     }
@@ -531,8 +513,6 @@
 
     private void setHasDismissedQuickScrubOnboardingOnce(
             boolean hasDismissedQuickScrubOnboardingOnce) {
-        Log.d(TAG,
-                "setHasDismissedQuickScrubOnboardingOnce: " + hasDismissedQuickScrubOnboardingOnce);
         Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE,
                 hasDismissedQuickScrubOnboardingOnce);
     }
@@ -541,8 +521,15 @@
         return Prefs.getInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, 0);
     }
 
+    private void incrementOpenedOverviewFromHomeCount() {
+        int openedOverviewFromHomeCount = getOpenedOverviewFromHomeCount();
+        if (openedOverviewFromHomeCount >= SWIPE_UP_SHOW_ON_OVERVIEW_OPENED_FROM_HOME_COUNT) {
+            return;
+        }
+        setOpenedOverviewFromHomeCount(openedOverviewFromHomeCount + 1);
+    }
+
     private void setOpenedOverviewFromHomeCount(int openedOverviewFromHomeCount) {
-        Log.d(TAG, "setOpenedOverviewFromHomeCount: " + openedOverviewFromHomeCount);
         Prefs.putInt(mContext, OVERVIEW_OPENED_FROM_HOME_COUNT, openedOverviewFromHomeCount);
     }
 
@@ -550,8 +537,15 @@
         return Prefs.getInt(mContext, OVERVIEW_OPENED_COUNT, 0);
     }
 
+    private void incrementOpenedOverviewCount() {
+        int openedOverviewCount = getOpenedOverviewCount();
+        if (openedOverviewCount >= QUICK_SCRUB_SHOW_ON_OVERVIEW_OPENED_COUNT) {
+            return;
+        }
+        setOpenedOverviewCount(openedOverviewCount + 1);
+    }
+
     private void setOpenedOverviewCount(int openedOverviewCount) {
-        Log.d(TAG, "setOpenedOverviewCount: " + openedOverviewCount);
         Prefs.putInt(mContext, OVERVIEW_OPENED_COUNT, openedOverviewCount);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
index 364ed80..6a38797 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ActivatableNotificationView.java
@@ -515,6 +515,13 @@
         }
     }
 
+    @Override
+    public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+        super.setDistanceToTopRoundness(distanceToTopRoundness);
+        mBackgroundNormal.setDistanceToTopRoundness(distanceToTopRoundness);
+        mBackgroundDimmed.setDistanceToTopRoundness(distanceToTopRoundness);
+    }
+
     /**
      * Set an override tint color that is used for the background.
      *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
index d03da8f..f30fa6b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableNotificationRow.java
@@ -2795,6 +2795,24 @@
     }
 
     @Override
+    public boolean topAmountNeedsClipping() {
+        if (isGroupExpanded()) {
+            return true;
+        }
+        if (isGroupExpansionChanging()) {
+            return true;
+        }
+        if (getShowingLayout().shouldClipToRounding(true /* topRounded */,
+                false /* bottomRounded */)) {
+            return true;
+        }
+        if (mGuts != null && mGuts.getAlpha() != 0.0f) {
+            return true;
+        }
+        return false;
+    }
+
+    @Override
     protected boolean childNeedsClipping(View child) {
         if (child instanceof NotificationContentView) {
             NotificationContentView contentView = (NotificationContentView) child;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
index 67268c0..edfa61b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/ExpandableOutlineView.java
@@ -76,7 +76,7 @@
      * it is moved. Otherwise, the translation is set on the {@code ExpandableOutlineView} itself.
      */
     protected boolean mShouldTranslateContents;
-    private boolean mClipRoundedToClipTopAmount;
+    private boolean mTopAmountRounded;
     private float mDistanceToTopRoundness = -1;
     private float mExtraWidthForClipping;
     private int mMinimumHeightForClipping = 0;
@@ -85,7 +85,8 @@
         @Override
         public void getOutline(View view, Outline outline) {
             if (!mCustomOutline && mCurrentTopRoundness == 0.0f
-                    && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners) {
+                    && mCurrentBottomRoundness == 0.0f && !mAlwaysRoundBothCorners
+                    && !mTopAmountRounded) {
                 int translation = mShouldTranslateContents ? (int) getTranslation() : 0;
                 int left = Math.max(translation, 0);
                 int top = mClipTopAmount + mBackgroundTop;
@@ -145,9 +146,9 @@
             return EMPTY_PATH;
         }
         float topRoundness = mAlwaysRoundBothCorners
-                ? mOutlineRadius : mCurrentTopRoundness * mOutlineRadius;
+                ? mOutlineRadius : getCurrentBackgroundRadiusTop();
         float bottomRoundness = mAlwaysRoundBothCorners
-                ? mOutlineRadius : mCurrentBottomRoundness * mOutlineRadius;
+                ? mOutlineRadius : getCurrentBackgroundRadiusBottom();
         if (topRoundness + bottomRoundness > height) {
             float overShoot = topRoundness + bottomRoundness - height;
             topRoundness -= overShoot * mCurrentTopRoundness
@@ -203,7 +204,7 @@
     protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
         canvas.save();
         Path intersectPath = null;
-        if (mClipRoundedToClipTopAmount) {
+        if (mTopAmountRounded && topAmountNeedsClipping()) {
             int left = (int) (- mExtraWidthForClipping / 2.0f);
             int top = (int) (mClipTopAmount - mDistanceToTopRoundness);
             int right = getWidth() + (int) (mExtraWidthForClipping + left);
@@ -248,9 +249,9 @@
     public void setDistanceToTopRoundness(float distanceToTopRoundness) {
         super.setDistanceToTopRoundness(distanceToTopRoundness);
         if (distanceToTopRoundness != mDistanceToTopRoundness) {
-            mClipRoundedToClipTopAmount = distanceToTopRoundness >= 0;
+            mTopAmountRounded = distanceToTopRoundness >= 0;
             mDistanceToTopRoundness = distanceToTopRoundness;
-            invalidate();
+            applyRoundness();
         }
     }
 
@@ -258,9 +259,12 @@
         return false;
     }
 
+    public boolean topAmountNeedsClipping() {
+        return true;
+    }
+
     protected boolean isClippingNeeded() {
         return mAlwaysRoundBothCorners || mCustomOutline || getTranslation() != 0 ;
-
     }
 
     private void initDimens() {
@@ -296,6 +300,11 @@
     }
 
     public float getCurrentBackgroundRadiusTop() {
+        // If this view is top amount notification view, it should always has round corners on top.
+        // It will be applied with applyRoundness()
+        if (mTopAmountRounded) {
+            return mOutlineRadius;
+        }
         return mCurrentTopRoundness * mOutlineRadius;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
index 0ff4dde..969e9d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationBackgroundView.java
@@ -53,6 +53,9 @@
     private int mDrawableAlpha = 255;
     private boolean mIsPressedAllowed;
 
+    private boolean mTopAmountRounded;
+    private float mDistanceToTopRoundness;
+
     public NotificationBackgroundView(Context context, AttributeSet attrs) {
         super(context, attrs);
         mDontModifyCorners = getResources().getBoolean(
@@ -74,6 +77,7 @@
 
     private void draw(Canvas canvas, Drawable drawable) {
         if (drawable != null) {
+            int top = mBackgroundTop;
             int bottom = mActualHeight;
             if (mBottomIsRounded && mBottomAmountClips && !mExpandAnimationRunning) {
                 bottom -= mClipBottomAmount;
@@ -84,7 +88,14 @@
                 left = (int) ((getWidth() - mActualWidth) / 2.0f);
                 right = (int) (left + mActualWidth);
             }
-            drawable.setBounds(left, mBackgroundTop, right, bottom);
+            if (mTopAmountRounded) {
+                int clipTop = (int) (mClipTopAmount - mDistanceToTopRoundness);
+                top += clipTop;
+                if (clipTop >= 0) {
+                    bottom += clipTop;
+                }
+            }
+            drawable.setBounds(left, top, right, bottom);
             drawable.draw(canvas);
         }
     }
@@ -165,6 +176,14 @@
         invalidate();
     }
 
+    public void setDistanceToTopRoundness(float distanceToTopRoundness) {
+        if (distanceToTopRoundness != mDistanceToTopRoundness) {
+            mTopAmountRounded = distanceToTopRoundness >= 0;
+            mDistanceToTopRoundness = distanceToTopRoundness;
+            invalidate();
+        }
+    }
+
     @Override
     public boolean hasOverlappingRendering() {
 
@@ -198,6 +217,9 @@
     }
 
     public void setRoundness(float topRoundness, float bottomRoundNess) {
+        if (topRoundness == mCornerRadii[0] && bottomRoundNess == mCornerRadii[4]) {
+            return;
+        }
         mBottomIsRounded = bottomRoundNess != 0.0f;
         mCornerRadii[0] = topRoundness;
         mCornerRadii[1] = topRoundness;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
index 58d3b9a..0bd3cc7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardStatusBarView.java
@@ -90,6 +90,11 @@
     private ViewGroup mStatusIconArea;
     private int mLayoutState = LAYOUT_NONE;
 
+    /**
+     * Draw this many pixels into the left/right side of the cutout to optimally use the space
+     */
+    private int mCutoutSideNudge = 0;
+
     public KeyguardStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
     }
@@ -158,6 +163,8 @@
                 R.dimen.system_icons_switcher_hidden_expanded_margin);
         mSystemIconsBaseMargin = res.getDimensionPixelSize(
                 R.dimen.system_icons_super_container_avatarless_margin_end);
+        mCutoutSideNudge = getResources().getDimensionPixelSize(
+                R.dimen.display_cutout_margin_consumption);
     }
 
     private void updateVisibilities() {
@@ -266,6 +273,8 @@
 
         mCutoutSpace.setVisibility(View.VISIBLE);
         RelativeLayout.LayoutParams lp = (LayoutParams) mCutoutSpace.getLayoutParams();
+        bounds.left = bounds.left + mCutoutSideNudge;
+        bounds.right = bounds.right - mCutoutSideNudge;
         lp.width = bounds.width();
         lp.height = bounds.height();
         lp.addRule(RelativeLayout.CENTER_IN_PARENT);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
index 68359bf..9acac22 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarFragment.java
@@ -1144,6 +1144,8 @@
             mRoot.postOnAnimationDelayed(mRipple, RIPPLE_OFFSET_MS);
             mRoot.postOnAnimationDelayed(mRipple, RIPPLE_INTERVAL_MS);
             mRoot.postOnAnimationDelayed(mRipple, 2*RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 3*RIPPLE_INTERVAL_MS);
+            mRoot.postOnAnimationDelayed(mRipple, 4*RIPPLE_INTERVAL_MS);
         }
 
         public void stop() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
index 4885c2f..e6f2c33 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarInflaterView.java
@@ -34,11 +34,12 @@
 import android.widget.Space;
 
 import com.android.systemui.Dependency;
+import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.PluginListener;
 import com.android.systemui.plugins.PluginManager;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider;
-import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseFrameLayout;
+import com.android.systemui.statusbar.phone.ReverseLinearLayout.ReverseRelativeLayout;
 import com.android.systemui.statusbar.policy.KeyButtonView;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
@@ -67,6 +68,7 @@
     public static final String KEY = "key";
     public static final String LEFT = "left";
     public static final String RIGHT = "right";
+    public static final String CONTEXTUAL = "contextual";
 
     public static final String GRAVITY_SEPARATOR = ";";
     public static final String BUTTON_SEPARATOR = ",";
@@ -97,6 +99,9 @@
     private View mLastLandscape;
 
     private boolean mAlternativeOrder;
+    private boolean mUsingCustomLayout;
+
+    private OverviewProxyService mOverviewProxyService;
 
     public NavigationBarInflaterView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -105,6 +110,7 @@
                 context.getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
         Mode displayMode = mDisplay.getMode();
         isRot0Landscape = displayMode.getPhysicalWidth() > displayMode.getPhysicalHeight();
+        mOverviewProxyService = Dependency.get(OverviewProxyService.class);
     }
 
     private void createInflaters() {
@@ -136,7 +142,10 @@
     }
 
     protected String getDefaultLayout() {
-        return mContext.getString(R.string.config_navBarLayout);
+        final int defaultResource = mOverviewProxyService.shouldShowSwipeUpUI()
+                ? R.string.config_navBarLayoutQuickstep
+                : R.string.config_navBarLayout;
+        return mContext.getString(defaultResource);
     }
 
     @Override
@@ -159,6 +168,7 @@
     public void onTuningChanged(String key, String newValue) {
         if (NAV_BAR_VIEWS.equals(key)) {
             if (!Objects.equals(mCurrentLayout, newValue)) {
+                mUsingCustomLayout = newValue != null;
                 clearViews();
                 inflateLayout(newValue);
             }
@@ -168,6 +178,18 @@
         }
     }
 
+    public void onLikelyDefaultLayoutChange() {
+        // Don't override custom layouts
+        if (mUsingCustomLayout) return;
+
+        // Reevaluate new layout
+        final String newValue = getDefaultLayout();
+        if (!Objects.equals(mCurrentLayout, newValue)) {
+            clearViews();
+            inflateLayout(newValue);
+        }
+    }
+
     public void setButtonDispatchers(SparseArray<ButtonDispatcher> buttonDispatchers) {
         mButtonDispatchers = buttonDispatchers;
         for (int i = 0; i < buttonDispatchers.size(); i++) {
@@ -178,10 +200,12 @@
     public void updateButtonDispatchersCurrentView() {
         if (mButtonDispatchers != null) {
             final int rotation = mDisplay.getRotation();
-            final View view = rotation == Surface.ROTATION_0 || rotation == Surface.ROTATION_180
-                    ? mRot0 : mRot90;
+            final boolean portrait = rotation == Surface.ROTATION_0
+                    || rotation == Surface.ROTATION_180;
+            final View view = portrait ? mRot0 : mRot90;
             for (int i = 0; i < mButtonDispatchers.size(); i++) {
-                mButtonDispatchers.valueAt(i).setCurrentView(view);
+                final ButtonDispatcher dispatcher = mButtonDispatchers.valueAt(i);
+                dispatcher.setCurrentView(view);
             }
         }
     }
@@ -288,8 +312,8 @@
         addToDispatchers(v);
         View lastView = landscape ? mLastLandscape : mLastPortrait;
         View accessibilityView = v;
-        if (v instanceof ReverseFrameLayout) {
-            accessibilityView = ((ReverseFrameLayout) v).getChildAt(0);
+        if (v instanceof ReverseRelativeLayout) {
+            accessibilityView = ((ReverseRelativeLayout) v).getChildAt(0);
         }
         if (lastView != null) {
             accessibilityView.setAccessibilityTraversalAfter(lastView.getId());
@@ -307,21 +331,33 @@
         if (sizeStr == null) return v;
 
         if (sizeStr.contains(WEIGHT_SUFFIX)) {
+            // To support gravity, wrap in RelativeLayout and apply gravity to it.
+            // Children wanting to use gravity must be smaller then the frame.
             float weight = Float.parseFloat(sizeStr.substring(0, sizeStr.indexOf(WEIGHT_SUFFIX)));
-            FrameLayout frame = new ReverseFrameLayout(mContext);
+            ReverseRelativeLayout frame = new ReverseRelativeLayout(mContext);
             LayoutParams childParams = new LayoutParams(v.getLayoutParams());
-            if (sizeStr.endsWith(WEIGHT_CENTERED_SUFFIX)) {
-                childParams.gravity = Gravity.CENTER;
-            } else {
-                childParams.gravity = landscape ? (start ? Gravity.BOTTOM : Gravity.TOP)
-                        : (start ? Gravity.START : Gravity.END);
-            }
+
+            // Compute gravity to apply
+            int gravity = (landscape) ? (start ? Gravity.TOP : Gravity.BOTTOM)
+                    : (start ? Gravity.START : Gravity.END);
+            if (sizeStr.endsWith(WEIGHT_CENTERED_SUFFIX)) gravity = Gravity.CENTER;
+
+            // Set default gravity, flipped if needed in reversed layouts (270 RTL and 90 LTR)
+            frame.setDefaultGravity(gravity);
+            frame.setGravity(gravity); // Apply gravity to root
+
             frame.addView(v, childParams);
+
+            // Use weighting to set the width of the frame
             frame.setLayoutParams(new LinearLayout.LayoutParams(0, MATCH_PARENT, weight));
+
+            // Ensure ripples can be drawn outside bounds
             frame.setClipChildren(false);
             frame.setClipToPadding(false);
+
             return frame;
         }
+
         float size = Float.parseFloat(sizeStr);
         ViewGroup.LayoutParams params = v.getLayoutParams();
         params.width = (int) (params.width * size);
@@ -355,6 +391,8 @@
             v = inflater.inflate(R.layout.nav_key_space, parent, false);
         } else if (CLIPBOARD.equals(button)) {
             v = inflater.inflate(R.layout.clipboard, parent, false);
+        } else if (CONTEXTUAL.equals(button)) {
+            v = inflater.inflate(R.layout.contextual, parent, false);
         } else if (button.startsWith(KEY)) {
             String uri = extractImage(button);
             int code = extractKeycode(button);
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 a907bdd..6c66cab 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -117,6 +117,7 @@
     private Rect mRecentsButtonBounds = new Rect();
     private Rect mRotationButtonBounds = new Rect();
     private int[] mTmpPosition = new int[2];
+    private Rect mTmpRect = new Rect();
 
     private KeyButtonDrawable mBackIcon;
     private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon;
@@ -604,6 +605,7 @@
         }
 
         updateNavButtonIcons();
+        updateSlippery();
     }
 
     public void updateNavButtonIcons() {
@@ -745,6 +747,12 @@
 
     public void updateStates() {
         final boolean showSwipeUpUI = mOverviewProxyService.shouldShowSwipeUpUI();
+
+        if (mNavigationInflaterView != null) {
+            // Reinflate the navbar if needed, no-op unless the swipe up state changes
+            mNavigationInflaterView.onLikelyDefaultLayoutChange();
+        }
+
         updateSlippery();
         reloadNavIcons();
         updateNavButtonIcons();
@@ -869,14 +877,27 @@
 
     public boolean isRotateButtonVisible() { return mShowRotateButton; }
 
-    public void setMenuContainerVisibility(boolean visible) {
-        getMenuContainer().setAlpha(visible ? 1 : 0, true /* animate */);
+    /**
+     * @return the button at the given {@param x} and {@param y}.
+     */
+    ButtonDispatcher getButtonAtPosition(int x, int y) {
+        for (int i = 0; i < mButtonDispatchers.size(); i++) {
+            ButtonDispatcher button = mButtonDispatchers.valueAt(i);
+            View buttonView = button.getCurrentView();
+            if (buttonView != null) {
+                buttonView.getHitRect(mTmpRect);
+                offsetDescendantRectToMyCoords(buttonView, mTmpRect);
+                if (mTmpRect.contains(x, y)) {
+                    return button;
+                }
+            }
+        }
+        return null;
     }
 
     @Override
     public void onFinishInflate() {
-        mNavigationInflaterView = (NavigationBarInflaterView) findViewById(
-                R.id.navigation_inflater);
+        mNavigationInflaterView = findViewById(R.id.navigation_inflater);
         mNavigationInflaterView.setButtonDispatchers(mButtonDispatchers);
 
         getImeSwitchButton().setOnClickListener(mImeSwitcherClickListener);
@@ -1169,10 +1190,11 @@
                 + " " + visibilityToString(getWindowVisibility())
                 + (offscreen ? " OFFSCREEN!" : ""));
 
-        pw.println(String.format("      mCurrentView: id=%s (%dx%d) %s",
+        pw.println(String.format("      mCurrentView: id=%s (%dx%d) %s %f",
                         getResourceName(getCurrentView().getId()),
                         getCurrentView().getWidth(), getCurrentView().getHeight(),
-                        visibilityToString(getCurrentView().getVisibility())));
+                        visibilityToString(getCurrentView().getVisibility()),
+                        getCurrentView().getAlpha()));
 
         pw.println(String.format("      disabled=0x%08x vertical=%s menu=%s",
                         mDisabledFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
index 01582d0..5477f88 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBarView.java
@@ -74,6 +74,10 @@
     private View mCutoutSpace;
     @Nullable
     private DisplayCutout mDisplayCutout;
+    /**
+     * Draw this many pixels into the left/right side of the cutout to optimally use the space
+     */
+    private int mCutoutSideNudge = 0;
 
     public PhoneStatusBarView(Context context, AttributeSet attrs) {
         super(context, attrs);
@@ -98,6 +102,8 @@
         mBarTransitions.init();
         mBattery = findViewById(R.id.battery);
         mCutoutSpace = findViewById(R.id.cutout_space_view);
+
+        updateResources();
     }
 
     @Override
@@ -280,6 +286,9 @@
     }
 
     public void updateResources() {
+        mCutoutSideNudge = getResources().getDimensionPixelSize(
+                R.dimen.display_cutout_margin_consumption);
+
         ViewGroup.LayoutParams layoutParams = getLayoutParams();
         layoutParams.height = getResources().getDimensionPixelSize(
                 R.dimen.status_bar_height);
@@ -311,6 +320,8 @@
         Rect bounds = new Rect();
         boundsFromDirection(mDisplayCutout, Gravity.TOP, bounds);
 
+        bounds.left = bounds.left + mCutoutSideNudge;
+        bounds.right = bounds.right - mCutoutSideNudge;
         lp.width = bounds.width();
         lp.height = bounds.height();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
index d9ba313..b55fe47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/QuickStepController.java
@@ -16,20 +16,30 @@
 
 package com.android.systemui.statusbar.phone;
 
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
+import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
+import static com.android.systemui.Interpolators.ALPHA_IN;
+import static com.android.systemui.Interpolators.ALPHA_OUT;
+import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
+import static com.android.systemui.OverviewProxyService.TAG_OPS;
+
 import android.animation.Animator;
 import android.animation.AnimatorListenerAdapter;
 import android.animation.AnimatorSet;
 import android.animation.ArgbEvaluator;
 import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
 import android.animation.ValueAnimator;
 import android.animation.ValueAnimator.AnimatorUpdateListener;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
 import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.util.FloatProperty;
 import android.util.Log;
 import android.util.Slog;
 import android.view.MotionEvent;
@@ -46,30 +56,22 @@
 import com.android.systemui.shared.recents.utilities.Utilities;
 import com.android.systemui.shared.system.NavigationBarCompat;
 
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_LEFT;
-import static android.view.WindowManagerPolicyConstants.NAV_BAR_BOTTOM;
-import static com.android.systemui.OverviewProxyService.DEBUG_OVERVIEW_PROXY;
-import static com.android.systemui.OverviewProxyService.TAG_OPS;
-import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_HOME;
-
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub.
  */
 public class QuickStepController implements GestureHelper {
 
     private static final String TAG = "QuickStepController";
-    private static final int ANIM_DURATION_MS = 200;
+    private static final int ANIM_IN_DURATION_MS = 150;
+    private static final int ANIM_OUT_DURATION_MS = 100;
 
     private NavigationBarView mNavigationBarView;
 
     private boolean mQuickScrubActive;
     private boolean mAllowGestureDetection;
     private boolean mQuickStepStarted;
-    private float mDownOffset;
-    private float mTranslation;
     private int mTouchDownX;
     private int mTouchDownY;
-    private boolean mDragScrubActive;
     private boolean mDragPositive;
     private boolean mIsVertical;
     private boolean mIsRTL;
@@ -77,69 +79,67 @@
     private int mLightTrackColor;
     private int mDarkTrackColor;
     private float mDarkIntensity;
-    private View mHomeButtonView;
+    private AnimatorSet mTrackAnimator;
+    private ButtonDispatcher mHitTarget;
+    private View mCurrentNavigationBarView;
 
     private final Handler mHandler = new Handler();
-    private final Interpolator mQuickScrubEndInterpolator = new DecelerateInterpolator();
     private final Rect mTrackRect = new Rect();
     private final Paint mTrackPaint = new Paint();
     private final OverviewProxyService mOverviewEventSender;
     private final int mTrackThickness;
-    private final int mTrackPadding;
-    private final ValueAnimator mTrackAnimator;
-    private final ValueAnimator mButtonAnimator;
-    private final AnimatorSet mQuickScrubEndAnimator;
+    private final int mTrackEndPadding;
     private final Context mContext;
     private final Matrix mTransformGlobalMatrix = new Matrix();
     private final Matrix mTransformLocalMatrix = new Matrix();
     private final ArgbEvaluator mTrackColorEvaluator = new ArgbEvaluator();
 
-    private final AnimatorUpdateListener mTrackAnimatorListener = valueAnimator -> {
-        mTrackAlpha = (float) valueAnimator.getAnimatedValue();
-        mNavigationBarView.invalidate();
+    private final FloatProperty<QuickStepController> mTrackAlphaProperty =
+            new FloatProperty<QuickStepController>("TrackAlpha") {
+        @Override
+        public void setValue(QuickStepController controller, float alpha) {
+            mTrackAlpha = alpha;
+            mNavigationBarView.invalidate();
+        }
+
+        @Override
+        public Float get(QuickStepController controller) {
+            return mTrackAlpha;
+        }
     };
 
-    private final AnimatorUpdateListener mButtonTranslationListener = animator -> {
-        int pos = (int) animator.getAnimatedValue();
-        if (!mQuickScrubActive) {
-            pos = mDragPositive ? Math.min((int) mTranslation, pos) : Math.max((int) mTranslation, pos);
+    private final FloatProperty<QuickStepController> mNavBarAlphaProperty =
+            new FloatProperty<QuickStepController>("NavBarAlpha") {
+        @Override
+        public void setValue(QuickStepController controller, float alpha) {
+            if (mCurrentNavigationBarView != null) {
+                mCurrentNavigationBarView.setAlpha(alpha);
+            }
         }
-        if (mIsVertical) {
-            mHomeButtonView.setTranslationY(pos);
-        } else {
-            mHomeButtonView.setTranslationX(pos);
+
+        @Override
+        public Float get(QuickStepController controller) {
+            if (mCurrentNavigationBarView != null) {
+                return mCurrentNavigationBarView.getAlpha();
+            }
+            return 1f;
         }
     };
 
     private AnimatorListenerAdapter mQuickScrubEndListener = new AnimatorListenerAdapter() {
         @Override
         public void onAnimationEnd(Animator animation) {
-            mQuickScrubActive = false;
-            mDragScrubActive = false;
-            mTranslation = 0;
-            mQuickScrubEndAnimator.setCurrentPlayTime(mQuickScrubEndAnimator.getDuration());
-            mHomeButtonView = null;
+            resetQuickScrub();
         }
     };
 
     public QuickStepController(Context context) {
+        final Resources res = context.getResources();
         mContext = context;
         mOverviewEventSender = Dependency.get(OverviewProxyService.class);
-        mTrackThickness = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_thickness);
-        mTrackPadding = getDimensionPixelSize(mContext, R.dimen.nav_quick_scrub_track_edge_padding);
+        mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
+        mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
         mTrackPaint.setAlpha(0);
-
-        mTrackAnimator = ObjectAnimator.ofFloat();
-        mTrackAnimator.addUpdateListener(mTrackAnimatorListener);
-        mTrackAnimator.setFloatValues(0);
-        mButtonAnimator = ObjectAnimator.ofInt();
-        mButtonAnimator.addUpdateListener(mButtonTranslationListener);
-        mButtonAnimator.setIntValues(0);
-        mQuickScrubEndAnimator = new AnimatorSet();
-        mQuickScrubEndAnimator.playTogether(mTrackAnimator, mButtonAnimator);
-        mQuickScrubEndAnimator.setDuration(ANIM_DURATION_MS);
-        mQuickScrubEndAnimator.addListener(mQuickScrubEndListener);
-        mQuickScrubEndAnimator.setInterpolator(mQuickScrubEndInterpolator);
     }
 
     public void setComponents(NavigationBarView navigationBarView) {
@@ -170,24 +170,28 @@
     private boolean handleTouchEvent(MotionEvent event) {
         if (mOverviewEventSender.getProxy() == null || (!mNavigationBarView.isQuickScrubEnabled()
                 && !mNavigationBarView.isQuickStepSwipeUpEnabled())) {
-            mNavigationBarView.getHomeButton().setDelayTouchFeedback(false /* delay */);
             return false;
         }
         mNavigationBarView.requestUnbufferedDispatch(event);
 
-        final ButtonDispatcher homeButton = mNavigationBarView.getHomeButton();
-        final boolean homePressed = mNavigationBarView.getDownHitTarget() == HIT_TARGET_HOME;
         int action = event.getActionMasked();
         switch (action) {
             case MotionEvent.ACTION_DOWN: {
                 int x = (int) event.getX();
                 int y = (int) event.getY();
+
                 // End any existing quickscrub animations before starting the new transition
-                if (mHomeButtonView != null) {
-                    mQuickScrubEndAnimator.end();
+                if (mTrackAnimator != null) {
+                    mTrackAnimator.end();
+                    mTrackAnimator = null;
                 }
-                mHomeButtonView = homeButton.getCurrentView();
-                homeButton.setDelayTouchFeedback(true /* delay */);
+
+                mCurrentNavigationBarView = mNavigationBarView.getCurrentView();
+                mHitTarget = mNavigationBarView.getButtonAtPosition(x, y);
+                if (mHitTarget != null) {
+                    // Pre-emptively delay the touch feedback for the button that we just touched
+                    mHitTarget.setDelayTouchFeedback(true);
+                }
                 mTouchDownX = x;
                 mTouchDownY = y;
                 mTransformGlobalMatrix.set(Matrix.IDENTITY_MATRIX);
@@ -199,7 +203,7 @@
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (mQuickStepStarted || !mAllowGestureDetection || mHomeButtonView == null){
+                if (mQuickStepStarted || !mAllowGestureDetection){
                     break;
                 }
                 int x = (int) event.getX();
@@ -207,7 +211,7 @@
                 int xDiff = Math.abs(x - mTouchDownX);
                 int yDiff = Math.abs(y - mTouchDownY);
 
-                boolean exceededScrubTouchSlop, exceededSwipeUpTouchSlop, exceededScrubDragSlop;
+                boolean exceededScrubTouchSlop, exceededSwipeUpTouchSlop;
                 int pos, touchDown, offset, trackSize;
 
                 if (mIsVertical) {
@@ -215,8 +219,6 @@
                             yDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && yDiff > xDiff;
                     exceededSwipeUpTouchSlop =
                             xDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && xDiff > yDiff;
-                    exceededScrubDragSlop =
-                            yDiff > NavigationBarCompat.getQuickScrubDragSlopPx() && yDiff > xDiff;
                     pos = y;
                     touchDown = mTouchDownY;
                     offset = pos - mTrackRect.top;
@@ -226,8 +228,6 @@
                             xDiff > NavigationBarCompat.getQuickScrubTouchSlopPx() && xDiff > yDiff;
                     exceededSwipeUpTouchSlop =
                             yDiff > NavigationBarCompat.getQuickStepTouchSlopPx() && yDiff > xDiff;
-                    exceededScrubDragSlop =
-                            xDiff > NavigationBarCompat.getQuickScrubDragSlopPx() && xDiff > yDiff;
                     pos = x;
                     touchDown = mTouchDownX;
                     offset = pos - mTrackRect.left;
@@ -242,8 +242,8 @@
                     break;
                 }
 
-                // Do not handle quick scrub if disabled or hit target is not home button
-                if (!homePressed || !mNavigationBarView.isQuickScrubEnabled()) {
+                // Do not handle quick scrub if disabled
+                if (!mNavigationBarView.isQuickScrubEnabled()) {
                     break;
                 }
 
@@ -253,41 +253,23 @@
 
                 final boolean allowDrag = !mDragPositive
                         ? offset < 0 && pos < touchDown : offset >= 0 && pos > touchDown;
+                float scrubFraction = Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
                 if (allowDrag) {
-                    // Passing the drag slop is for visual feedback and will not initiate anything
-                    if (!mDragScrubActive && exceededScrubDragSlop) {
-                        mDownOffset = offset;
-                        mDragScrubActive = true;
-                    }
-
                     // Passing the drag slop then touch slop will start quick step
                     if (!mQuickScrubActive && exceededScrubTouchSlop) {
-                        homeButton.abortCurrentGesture();
                         startQuickScrub();
                     }
                 }
 
-                if ((mQuickScrubActive || mDragScrubActive) && (mDragPositive && offset >= 0
+                if (mQuickScrubActive && (mDragPositive && offset >= 0
                         || !mDragPositive && offset <= 0)) {
-                    mTranslation = !mDragPositive
-                            ? Utilities.clamp(offset - mDownOffset, -trackSize, 0)
-                            : Utilities.clamp(offset - mDownOffset, 0, trackSize);
-                    if (mQuickScrubActive) {
-                        float scrubFraction =
-                                Utilities.clamp(Math.abs(offset) * 1f / trackSize, 0, 1);
-                        try {
-                            mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
-                            if (DEBUG_OVERVIEW_PROXY) {
-                                Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
-                            }
-                        } catch (RemoteException e) {
-                            Log.e(TAG, "Failed to send progress of quick scrub.", e);
+                    try {
+                        mOverviewEventSender.getProxy().onQuickScrubProgress(scrubFraction);
+                        if (DEBUG_OVERVIEW_PROXY) {
+                            Log.d(TAG_OPS, "Quick Scrub Progress:" + scrubFraction);
                         }
-                    }
-                    if (mIsVertical) {
-                        mHomeButtonView.setTranslationY(mTranslation);
-                    } else {
-                        mHomeButtonView.setTranslationX(mTranslation);
+                    } catch (RemoteException e) {
+                        Log.e(TAG, "Failed to send progress of quick scrub.", e);
                     }
                 }
                 break;
@@ -321,21 +303,23 @@
 
     @Override
     public void onLayout(boolean changed, int left, int top, int right, int bottom) {
-        final int width = (right - left) - mNavigationBarView.getPaddingEnd()
-                - mNavigationBarView.getPaddingStart();
-        final int height = (bottom - top) - mNavigationBarView.getPaddingBottom()
-                - mNavigationBarView.getPaddingTop();
+        final int paddingLeft = mNavigationBarView.getPaddingLeft();
+        final int paddingTop = mNavigationBarView.getPaddingTop();
+        final int paddingRight = mNavigationBarView.getPaddingRight();
+        final int paddingBottom = mNavigationBarView.getPaddingBottom();
+        final int width = (right - left) - paddingRight - paddingLeft;
+        final int height = (bottom - top) - paddingBottom - paddingTop;
         final int x1, x2, y1, y2;
         if (mIsVertical) {
-            x1 = (width - mTrackThickness) / 2 + mNavigationBarView.getPaddingLeft();
+            x1 = (width - mTrackThickness) / 2 + paddingLeft;
             x2 = x1 + mTrackThickness;
-            y1 = mDragPositive ? height / 2 : mTrackPadding;
-            y2 = y1 + height / 2 - mTrackPadding;
+            y1 = paddingTop + mTrackEndPadding;
+            y2 = y1 + height - 2 * mTrackEndPadding;
         } else {
-            y1 = (height - mTrackThickness) / 2 + mNavigationBarView.getPaddingTop();
+            y1 = (height - mTrackThickness) / 2 + paddingTop;
             y2 = y1 + mTrackThickness;
-            x1 = mDragPositive ? width / 2 : mTrackPadding;
-            x2 = x1 + width / 2 - mTrackPadding;
+            x1 = mNavigationBarView.getPaddingStart() + mTrackEndPadding;
+            x2 = x1 + width - 2 * mTrackEndPadding;
         }
         mTrackRect.set(x1, y1, x2, y2);
     }
@@ -386,24 +370,32 @@
             event.transform(mTransformLocalMatrix);
         }
         mOverviewEventSender.notifyQuickStepStarted();
-        mNavigationBarView.getHomeButton().abortCurrentGesture();
         mHandler.removeCallbacksAndMessages(null);
 
-        if (mDragScrubActive) {
+        if (mHitTarget != null) {
+            mHitTarget.abortCurrentGesture();
+        }
+
+        if (mQuickScrubActive) {
             animateEnd();
         }
     }
 
     private void startQuickScrub() {
-        if (!mQuickScrubActive && mDragScrubActive) {
+        if (!mQuickScrubActive) {
             mQuickScrubActive = true;
             mLightTrackColor = mContext.getColor(R.color.quick_step_track_background_light);
             mDarkTrackColor = mContext.getColor(R.color.quick_step_track_background_dark);
-            mTrackAnimator.setFloatValues(0, 1);
-            mTrackAnimator.start();
 
-            // Hide menu buttons on nav bar until quick scrub has ended
-            mNavigationBarView.setMenuContainerVisibility(false /* visible */);
+            ObjectAnimator trackAnimator = ObjectAnimator.ofFloat(this, mTrackAlphaProperty, 1f);
+            trackAnimator.setInterpolator(ALPHA_IN);
+            trackAnimator.setDuration(ANIM_IN_DURATION_MS);
+            ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 0f);
+            navBarAnimator.setInterpolator(ALPHA_OUT);
+            navBarAnimator.setDuration(ANIM_OUT_DURATION_MS);
+            mTrackAnimator = new AnimatorSet();
+            mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
+            mTrackAnimator.start();
 
             try {
                 mOverviewEventSender.getProxy().onQuickScrubStart();
@@ -414,32 +406,56 @@
                 Log.e(TAG, "Failed to send start of quick scrub.", e);
             }
             mOverviewEventSender.notifyQuickScrubStarted();
+
+            if (mHitTarget != null) {
+                mHitTarget.abortCurrentGesture();
+            }
         }
     }
 
     private void endQuickScrub(boolean animate) {
-        if (mQuickScrubActive || mDragScrubActive) {
+        if (mQuickScrubActive) {
             animateEnd();
-
-            // Restore the nav bar menu buttons visibility
-            mNavigationBarView.setMenuContainerVisibility(true /* visible */);
-
-            if (mQuickScrubActive) {
-                try {
-                    mOverviewEventSender.getProxy().onQuickScrubEnd();
-                    if (DEBUG_OVERVIEW_PROXY) {
-                        Log.d(TAG_OPS, "Quick Scrub End");
-                    }
-                } catch (RemoteException e) {
-                    Log.e(TAG, "Failed to send end of quick scrub.", e);
+            try {
+                mOverviewEventSender.getProxy().onQuickScrubEnd();
+                if (DEBUG_OVERVIEW_PROXY) {
+                    Log.d(TAG_OPS, "Quick Scrub End");
                 }
+            } catch (RemoteException e) {
+                Log.e(TAG, "Failed to send end of quick scrub.", e);
             }
         }
-        if (mHomeButtonView != null && !animate) {
-            mQuickScrubEndAnimator.end();
+        if (!animate) {
+            if (mTrackAnimator != null) {
+                mTrackAnimator.end();
+                mTrackAnimator = null;
+            }
         }
     }
 
+    private void animateEnd() {
+        if (mTrackAnimator != null) {
+            mTrackAnimator.cancel();
+        }
+
+        ObjectAnimator trackAnimator = ObjectAnimator.ofFloat(this, mTrackAlphaProperty, 0f);
+        trackAnimator.setInterpolator(ALPHA_OUT);
+        trackAnimator.setDuration(ANIM_OUT_DURATION_MS);
+        ObjectAnimator navBarAnimator = ObjectAnimator.ofFloat(this, mNavBarAlphaProperty, 1f);
+        navBarAnimator.setInterpolator(ALPHA_IN);
+        navBarAnimator.setDuration(ANIM_IN_DURATION_MS);
+        mTrackAnimator = new AnimatorSet();
+        mTrackAnimator.playTogether(trackAnimator, navBarAnimator);
+        mTrackAnimator.addListener(mQuickScrubEndListener);
+        mTrackAnimator.start();
+    }
+
+    private void resetQuickScrub() {
+        mQuickScrubActive = false;
+        mAllowGestureDetection = false;
+        mCurrentNavigationBarView = null;
+    }
+
     private boolean proxyMotionEvents(MotionEvent event) {
         final IOverviewProxy overviewProxy = mOverviewEventSender.getProxy();
         event.transform(mTransformGlobalMatrix);
@@ -459,15 +475,4 @@
         }
         return false;
     }
-
-    private void animateEnd() {
-        mButtonAnimator.setIntValues((int) mTranslation, 0);
-        mTrackAnimator.setFloatValues(mTrackAlpha, 0);
-        mQuickScrubEndAnimator.setCurrentPlayTime(0);
-        mQuickScrubEndAnimator.start();
-    }
-
-    private int getDimensionPixelSize(Context context, @DimenRes int resId) {
-        return context.getResources().getDimensionPixelSize(resId);
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
index bcbc345..d3ec187 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ReverseLinearLayout.java
@@ -17,10 +17,11 @@
 import android.annotation.Nullable;
 import android.content.Context;
 import android.util.AttributeSet;
+import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
-import android.widget.FrameLayout;
 import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
 
 import java.util.ArrayList;
 
@@ -48,7 +49,7 @@
 
     @Override
     public void addView(View child) {
-        reverseParams(child.getLayoutParams(), child);
+        reverseParams(child.getLayoutParams(), child, mIsLayoutReverse);
         if (mIsLayoutReverse) {
             super.addView(child, 0);
         } else {
@@ -58,7 +59,7 @@
 
     @Override
     public void addView(View child, ViewGroup.LayoutParams params) {
-        reverseParams(params, child);
+        reverseParams(params, child, mIsLayoutReverse);
         if (mIsLayoutReverse) {
             super.addView(child, 0, params);
         } else {
@@ -94,15 +95,17 @@
             }
             removeAllViews();
             for (int i = childCount - 1; i >= 0; i--) {
-                super.addView(childList.get(i));
+                final View child = childList.get(i);
+                super.addView(child);
             }
             mIsLayoutReverse = isLayoutReverse;
         }
     }
 
-    private static void reverseParams(ViewGroup.LayoutParams params, View child) {
+    private static void reverseParams(ViewGroup.LayoutParams params, View child,
+            boolean isLayoutReverse) {
         if (child instanceof Reversable) {
-            ((Reversable) child).reverse();
+            ((Reversable) child).reverse(isLayoutReverse);
         }
         if (child.getPaddingLeft() == child.getPaddingRight()
                 && child.getPaddingTop() == child.getPaddingBottom()) {
@@ -118,20 +121,48 @@
     }
 
     public interface Reversable {
-        void reverse();
+        void reverse(boolean isLayoutReverse);
     }
 
-    public static class ReverseFrameLayout extends FrameLayout implements Reversable {
+    public static class ReverseRelativeLayout extends RelativeLayout implements Reversable {
 
-        public ReverseFrameLayout(Context context) {
+        public ReverseRelativeLayout(Context context) {
             super(context);
         }
 
         @Override
-        public void reverse() {
-            for (int i = 0; i < getChildCount(); i++) {
-                View child = getChildAt(i);
-                reverseParams(child.getLayoutParams(), child);
+        public void reverse(boolean isLayoutReverse) {
+            updateGravity(isLayoutReverse);
+            reverseGroup(this, isLayoutReverse);
+        }
+
+        private int mDefaultGravity = Gravity.NO_GRAVITY;
+        public void setDefaultGravity(int gravity) {
+            mDefaultGravity = gravity;
+        }
+
+        public void updateGravity(boolean isLayoutReverse) {
+            // Flip gravity if top of bottom is used
+            if (mDefaultGravity != Gravity.TOP && mDefaultGravity != Gravity.BOTTOM) return;
+
+            // Use the default (intended for 270 LTR and 90 RTL) unless layout is otherwise
+            int gravityToApply = mDefaultGravity;
+            if (isLayoutReverse) {
+                gravityToApply = mDefaultGravity == Gravity.TOP ? Gravity.BOTTOM : Gravity.TOP;
+            }
+
+            if (getGravity() != gravityToApply) setGravity(gravityToApply);
+        }
+    }
+    
+    private static void reverseGroup(ViewGroup group, boolean isLayoutReverse) {
+        for (int i = 0; i < group.getChildCount(); i++) {
+            final View child = group.getChildAt(i);
+            reverseParams(child.getLayoutParams(), child, isLayoutReverse);
+
+            // Recursively reverse all children
+            if (child instanceof ViewGroup) {
+                reverseGroup((ViewGroup) child, isLayoutReverse);
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
index 7cd433a..384a6e7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarSignalPolicy.java
@@ -148,16 +148,31 @@
         boolean in = activityIn && mActivityEnabled && visible;
         boolean out = activityOut && mActivityEnabled && visible;
 
-        mWifiIconState.visible = visible;
-        mWifiIconState.resId = statusIcon.icon;
-        mWifiIconState.activityIn = in;
-        mWifiIconState.activityOut = out;
-        mWifiIconState.slot = mSlotWifi;
-        mWifiIconState.airplaneSpacerVisible = mIsAirplaneMode;
-        mWifiIconState.contentDescription = statusIcon.contentDescription;
+        WifiIconState newState = mWifiIconState.copy();
 
-        if (mWifiIconState.visible && mWifiIconState.resId > 0) {
-            mIconController.setSignalIcon(mSlotWifi, mWifiIconState.copy());
+        newState.visible = visible;
+        newState.resId = statusIcon.icon;
+        newState.activityIn = in;
+        newState.activityOut = out;
+        newState.slot = mSlotWifi;
+        newState.airplaneSpacerVisible = mIsAirplaneMode;
+        newState.contentDescription = statusIcon.contentDescription;
+
+        MobileIconState first = getFirstMobileState();
+        newState.signalSpacerVisible = first != null && first.typeId != 0;
+
+        updateWifiIconWithState(newState);
+        mWifiIconState = newState;
+    }
+
+    private void updateShowWifiSignalSpacer(WifiIconState state) {
+        MobileIconState first = getFirstMobileState();
+        state.signalSpacerVisible = first != null && first.typeId != 0;
+    }
+
+    private void updateWifiIconWithState(WifiIconState state) {
+        if (state.visible && state.resId > 0) {
+            mIconController.setSignalIcon(mSlotWifi, state);
             mIconController.setIconVisibility(mSlotWifi, true);
         } else {
             mIconController.setIconVisibility(mSlotWifi, false);
@@ -173,6 +188,9 @@
             return;
         }
 
+        // Visibility of the data type indicator changed
+        boolean typeChanged = statusType != state.typeId && (statusType == 0 || state.typeId == 0);
+
         state.visible = statusIcon.visible && !mBlockMobile;
         state.strengthId = statusIcon.icon;
         state.typeId = statusType;
@@ -184,6 +202,15 @@
 
         // Always send a copy to maintain value type semantics
         mIconController.setMobileIcons(mSlotMobile, MobileIconState.copyStates(mMobileStates));
+
+        if (typeChanged) {
+            WifiIconState wifiCopy = mWifiIconState.copy();
+            updateShowWifiSignalSpacer(wifiCopy);
+            if (!Objects.equals(wifiCopy, mWifiIconState)) {
+                updateWifiIconWithState(wifiCopy);
+                mWifiIconState = wifiCopy;
+            }
+        }
     }
 
     private MobileIconState getState(int subId) {
@@ -196,6 +223,14 @@
         return null;
     }
 
+    private MobileIconState getFirstMobileState() {
+        if (mMobileStates.size() > 0) {
+            return mMobileStates.get(0);
+        }
+
+        return null;
+    }
+
 
     /**
      * It is expected that a call to setSubs will be immediately followed by setMobileDataIndicators
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
index 85cfde8..12b6f9d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonView.java
@@ -16,6 +16,9 @@
 
 package com.android.systemui.statusbar.policy;
 
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
+import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
+
 import android.app.ActivityManager;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -41,20 +44,14 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.accessibility.AccessibilityNodeInfo;
 import android.widget.ImageView;
-
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.systemui.Dependency;
 import com.android.systemui.OverviewProxyService;
 import com.android.systemui.R;
 import com.android.systemui.plugins.statusbar.phone.NavBarButtonProvider.ButtonInterface;
-import com.android.systemui.shared.system.ActivityManagerWrapper;
 import com.android.systemui.shared.system.NavigationBarCompat;
 
-import static android.view.KeyEvent.KEYCODE_HOME;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_CLICK;
-import static android.view.accessibility.AccessibilityNodeInfo.ACTION_LONG_CLICK;
-
 public class KeyButtonView extends ImageView implements ButtonInterface {
     private static final String TAG = KeyButtonView.class.getSimpleName();
 
@@ -119,6 +116,7 @@
         mRipple = new KeyButtonRipple(context, this);
         mOverviewProxyService = Dependency.get(OverviewProxyService.class);
         setBackground(mRipple);
+        forceHasOverlappingRendering(false);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
index a2b33fa..7410069 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -760,7 +760,9 @@
     }
 
     private void updateClippingToTopRoundedCorner() {
-        Float clipStart = (float) mTopPadding + mAmbientState.getExpandAnimationTopChange();
+        Float clipStart = (float) mTopPadding
+                                 + mStackTranslation
+                                 + mAmbientState.getExpandAnimationTopChange();
         Float clipEnd = clipStart + mCornerRadius;
         boolean first = true;
         for (int i = 0; i < getChildCount(); i++) {
@@ -769,8 +771,7 @@
                 continue;
             }
             float start = child.getTranslationY();
-            float end = start + Math.max(child.getActualHeight() - child.getClipBottomAmount(),
-                    0);
+            float end = start + child.getActualHeight();
             boolean clip = clipStart > start && clipStart < end
                     || clipEnd >= start && clipEnd <= end;
             clip &= !(first && mOwnScrollY == 0);
@@ -3292,6 +3293,16 @@
             if (!childWasSwipedOut) {
                 Rect clipBounds = child.getClipBounds();
                 childWasSwipedOut = clipBounds != null && clipBounds.height() == 0;
+
+                if (childWasSwipedOut && child instanceof ExpandableView) {
+                    // Clean up any potential transient views if the child has already been swiped
+                    // out, as we won't be animating it further (due to its height already being
+                    // clipped to 0.
+                    ViewGroup transientContainer = ((ExpandableView) child).getTransientContainer();
+                    if (transientContainer != null) {
+                        transientContainer.removeTransientView(child);
+                    }
+                }
             }
             int animationType = childWasSwipedOut
                     ? AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e22a86e..c3f504f 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2442,97 +2442,107 @@
         }
     }
 
+    // This is a no-op if it's called with a message designating a network that has
+    // already been destroyed, because its reference will not be found in the relevant
+    // maps.
     private void handleAsyncChannelDisconnected(Message msg) {
         NetworkAgentInfo nai = mNetworkAgentInfos.get(msg.replyTo);
         if (nai != null) {
-            if (DBG) {
-                log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
-            }
-            // A network agent has disconnected.
-            // TODO - if we move the logic to the network agent (have them disconnect
-            // because they lost all their requests or because their score isn't good)
-            // then they would disconnect organically, report their new state and then
-            // disconnect the channel.
-            if (nai.networkInfo.isConnected()) {
-                nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
-                        null, null);
-            }
-            final boolean wasDefault = isDefaultNetwork(nai);
-            if (wasDefault) {
-                mDefaultInetConditionPublished = 0;
-                // Log default network disconnection before required book-keeping.
-                // Let rematchAllNetworksAndRequests() below record a new default network event
-                // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
-                // whose timestamps tell how long it takes to recover a default network.
-                long now = SystemClock.elapsedRealtime();
-                metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
-            }
-            notifyIfacesChangedForNetworkStats();
-            // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
-            // by other networks that are already connected. Perhaps that can be done by
-            // sending all CALLBACK_LOST messages (for requests, not listens) at the end
-            // of rematchAllNetworksAndRequests
-            notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
-            mKeepaliveTracker.handleStopAllKeepalives(nai,
-                    ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
-            for (String iface : nai.linkProperties.getAllInterfaceNames()) {
-                // Disable wakeup packet monitoring for each interface.
-                wakeupModifyInterface(iface, nai.networkCapabilities, false);
-            }
-            nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
-            mNetworkAgentInfos.remove(msg.replyTo);
-            nai.maybeStopClat();
-            synchronized (mNetworkForNetId) {
-                // Remove the NetworkAgent, but don't mark the netId as
-                // available until we've told netd to delete it below.
-                mNetworkForNetId.remove(nai.network.netId);
-            }
-            // Remove all previously satisfied requests.
-            for (int i = 0; i < nai.numNetworkRequests(); i++) {
-                NetworkRequest request = nai.requestAt(i);
-                NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
-                if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
-                    clearNetworkForRequest(request.requestId);
-                    sendUpdatedScoreToFactories(request, 0);
-                }
-            }
-            nai.clearLingerState();
-            if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
-                removeDataActivityTracking(nai);
-                notifyLockdownVpn(nai);
-                ensureNetworkTransitionWakelock(nai.name());
-            }
-            mLegacyTypeTracker.remove(nai, wasDefault);
-            if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
-                updateAllVpnsCapabilities();
-            }
-            rematchAllNetworksAndRequests(null, 0);
-            mLingerMonitor.noteDisconnect(nai);
-            if (nai.created) {
-                // Tell netd to clean up the configuration for this network
-                // (routing rules, DNS, etc).
-                // This may be slow as it requires a lot of netd shelling out to ip and
-                // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
-                // after we've rematched networks with requests which should make a potential
-                // fallback network the default or requested a new network from the
-                // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
-                // long time.
-                try {
-                    mNetd.removeNetwork(nai.network.netId);
-                } catch (Exception e) {
-                    loge("Exception removing network: " + e);
-                }
-                mDnsManager.removeNetwork(nai.network);
-            }
-            synchronized (mNetworkForNetId) {
-                mNetIdInUse.delete(nai.network.netId);
-            }
+            disconnectAndDestroyNetwork(nai);
         } else {
             NetworkFactoryInfo nfi = mNetworkFactoryInfos.remove(msg.replyTo);
             if (DBG && nfi != null) log("unregisterNetworkFactory for " + nfi.name);
         }
     }
 
+    // Destroys a network, remove references to it from the internal state managed by
+    // ConnectivityService, free its interfaces and clean up.
+    // Must be called on the Handler thread.
+    private void disconnectAndDestroyNetwork(NetworkAgentInfo nai) {
+        if (DBG) {
+            log(nai.name() + " got DISCONNECTED, was satisfying " + nai.numNetworkRequests());
+        }
+        // A network agent has disconnected.
+        // TODO - if we move the logic to the network agent (have them disconnect
+        // because they lost all their requests or because their score isn't good)
+        // then they would disconnect organically, report their new state and then
+        // disconnect the channel.
+        if (nai.networkInfo.isConnected()) {
+            nai.networkInfo.setDetailedState(NetworkInfo.DetailedState.DISCONNECTED,
+                    null, null);
+        }
+        final boolean wasDefault = isDefaultNetwork(nai);
+        if (wasDefault) {
+            mDefaultInetConditionPublished = 0;
+            // Log default network disconnection before required book-keeping.
+            // Let rematchAllNetworksAndRequests() below record a new default network event
+            // if there is a fallback. Taken together, the two form a X -> 0, 0 -> Y sequence
+            // whose timestamps tell how long it takes to recover a default network.
+            long now = SystemClock.elapsedRealtime();
+            metricsLogger().defaultNetworkMetrics().logDefaultNetworkEvent(now, null, nai);
+        }
+        notifyIfacesChangedForNetworkStats();
+        // TODO - we shouldn't send CALLBACK_LOST to requests that can be satisfied
+        // by other networks that are already connected. Perhaps that can be done by
+        // sending all CALLBACK_LOST messages (for requests, not listens) at the end
+        // of rematchAllNetworksAndRequests
+        notifyNetworkCallbacks(nai, ConnectivityManager.CALLBACK_LOST);
+        mKeepaliveTracker.handleStopAllKeepalives(nai,
+                ConnectivityManager.PacketKeepalive.ERROR_INVALID_NETWORK);
+        for (String iface : nai.linkProperties.getAllInterfaceNames()) {
+            // Disable wakeup packet monitoring for each interface.
+            wakeupModifyInterface(iface, nai.networkCapabilities, false);
+        }
+        nai.networkMonitor.sendMessage(NetworkMonitor.CMD_NETWORK_DISCONNECTED);
+        mNetworkAgentInfos.remove(nai.messenger);
+        nai.maybeStopClat();
+        synchronized (mNetworkForNetId) {
+            // Remove the NetworkAgent, but don't mark the netId as
+            // available until we've told netd to delete it below.
+            mNetworkForNetId.remove(nai.network.netId);
+        }
+        // Remove all previously satisfied requests.
+        for (int i = 0; i < nai.numNetworkRequests(); i++) {
+            NetworkRequest request = nai.requestAt(i);
+            NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
+            if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
+                clearNetworkForRequest(request.requestId);
+                sendUpdatedScoreToFactories(request, 0);
+            }
+        }
+        nai.clearLingerState();
+        if (nai.isSatisfyingRequest(mDefaultRequest.requestId)) {
+            removeDataActivityTracking(nai);
+            notifyLockdownVpn(nai);
+            ensureNetworkTransitionWakelock(nai.name());
+        }
+        mLegacyTypeTracker.remove(nai, wasDefault);
+        if (!nai.networkCapabilities.hasTransport(TRANSPORT_VPN)) {
+            updateAllVpnsCapabilities();
+        }
+        rematchAllNetworksAndRequests(null, 0);
+        mLingerMonitor.noteDisconnect(nai);
+        if (nai.created) {
+            // Tell netd to clean up the configuration for this network
+            // (routing rules, DNS, etc).
+            // This may be slow as it requires a lot of netd shelling out to ip and
+            // ip[6]tables to flush routes and remove the incoming packet mark rule, so do it
+            // after we've rematched networks with requests which should make a potential
+            // fallback network the default or requested a new network from the
+            // NetworkFactories, so network traffic isn't interrupted for an unnecessarily
+            // long time.
+            try {
+                mNetd.removeNetwork(nai.network.netId);
+            } catch (Exception e) {
+                loge("Exception removing network: " + e);
+            }
+            mDnsManager.removeNetwork(nai.network);
+        }
+        synchronized (mNetworkForNetId) {
+            mNetIdInUse.delete(nai.network.netId);
+        }
+    }
+
     // If this method proves to be too slow then we can maintain a separate
     // pendingIntent => NetworkRequestInfo map.
     // This method assumes that every non-null PendingIntent maps to exactly 1 NetworkRequestInfo.
@@ -5618,6 +5628,7 @@
                 }
                 updateUids(networkAgent, networkAgent.networkCapabilities, null);
             }
+            disconnectAndDestroyNetwork(networkAgent);
         } else if ((oldInfo != null && oldInfo.getState() == NetworkInfo.State.SUSPENDED) ||
                 state == NetworkInfo.State.SUSPENDED) {
             // going into or coming out of SUSPEND: rescore and notify
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 67a16bd..c25f8ff 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -20548,7 +20548,7 @@
         IPackageManager pm = AppGlobals.getPackageManager();
         ApplicationInfo app = null;
         try {
-            app = pm.getApplicationInfo(packageName, 0, userId);
+            app = pm.getApplicationInfo(packageName, STOCK_PM_FLAGS, userId);
         } catch (RemoteException e) {
             // can't happen; package manager is process-local
         }
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index afad0b1..7310fab 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -2554,6 +2554,10 @@
             final int displayId = mTmpOrderedDisplayIds.get(i);
             // If a display is registered in WM, it must also be available in AM.
             final ActivityDisplay display = getActivityDisplayOrCreateLocked(displayId);
+            if (display == null) {
+                // Looks like the display no longer exists in the system...
+                continue;
+            }
             for (int j = display.getChildCount() - 1; j >= 0; --j) {
                 final ActivityStack stack = display.getChildAt(j);
                 if (ignoreCurrent && stack == currentFocus) {
diff --git a/services/core/java/com/android/server/content/ContentService.java b/services/core/java/com/android/server/content/ContentService.java
index d7057f4..2c9a494 100644
--- a/services/core/java/com/android/server/content/ContentService.java
+++ b/services/core/java/com/android/server/content/ContentService.java
@@ -1310,10 +1310,10 @@
                 : ActivityManager.PROCESS_STATE_NONEXISTENT;
 
         if (procState <= ActivityManager.PROCESS_STATE_TOP) {
-            return ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP;
+            return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP;
         }
         if (procState <= ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND) {
-            return ContentResolver.SYNC_EXEMPTION_ACTIVE;
+            return ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET;
         }
         return ContentResolver.SYNC_EXEMPTION_NONE;
     }
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 33cf11b..0a640b8 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -1656,7 +1656,7 @@
         }
 
         if (syncOperation.syncExemptionFlag
-                == ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP) {
+                == ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP) {
             DeviceIdleController.LocalService dic =
                     LocalServices.getService(DeviceIdleController.LocalService.class);
             if (dic != null) {
@@ -1668,6 +1668,15 @@
             }
         }
 
+        if (syncOperation.isAppStandbyExempted()) {
+            final UsageStatsManagerInternal usmi = LocalServices.getService(
+                    UsageStatsManagerInternal.class);
+            if (usmi != null) {
+                usmi.reportExemptedSyncScheduled(syncOperation.owningPackage,
+                        UserHandle.getUserId(syncOperation.owningUid));
+            }
+        }
+
         getJobScheduler().scheduleAsPackage(b.build(), syncOperation.owningPackage,
                 syncOperation.target.userId, syncOperation.wakeLockName());
     }
diff --git a/services/core/java/com/android/server/content/SyncOperation.java b/services/core/java/com/android/server/content/SyncOperation.java
index d097563..25edf40 100644
--- a/services/core/java/com/android/server/content/SyncOperation.java
+++ b/services/core/java/com/android/server/content/SyncOperation.java
@@ -390,10 +390,10 @@
         switch (syncExemptionFlag) {
             case ContentResolver.SYNC_EXEMPTION_NONE:
                 break;
-            case ContentResolver.SYNC_EXEMPTION_ACTIVE:
+            case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
                 sb.append(" STANDBY-EXEMPTED");
                 break;
-            case ContentResolver.SYNC_EXEMPTION_ACTIVE_WITH_TEMP:
+            case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
                 sb.append(" STANDBY-EXEMPTED(TOP)");
                 break;
             default:
diff --git a/services/core/java/com/android/server/content/SyncStorageEngine.java b/services/core/java/com/android/server/content/SyncStorageEngine.java
index 6a343f8..11f0701 100644
--- a/services/core/java/com/android/server/content/SyncStorageEngine.java
+++ b/services/core/java/com/android/server/content/SyncStorageEngine.java
@@ -341,6 +341,7 @@
         boolean initialization;
         Bundle extras;
         int reason;
+        int syncExemptionFlag;
     }
 
     public static class DayStats {
@@ -1142,6 +1143,7 @@
             item.reason = op.reason;
             item.extras = op.extras;
             item.event = EVENT_START;
+            item.syncExemptionFlag = op.syncExemptionFlag;
             mSyncHistory.add(0, item);
             while (mSyncHistory.size() > MAX_HISTORY) {
                 mSyncHistory.remove(mSyncHistory.size()-1);
@@ -1262,6 +1264,20 @@
             SyncManager.formatDurationHMS(event, elapsedTime);
             event.append(" Reason=");
             event.append(SyncOperation.reasonToString(null, item.reason));
+            if (item.syncExemptionFlag != ContentResolver.SYNC_EXEMPTION_NONE) {
+                event.append(" Exemption=");
+                switch (item.syncExemptionFlag) {
+                    case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET:
+                        event.append("fg");
+                        break;
+                    case ContentResolver.SYNC_EXEMPTION_PROMOTE_BUCKET_WITH_TEMP:
+                        event.append("top");
+                        break;
+                    default:
+                        event.append(item.syncExemptionFlag);
+                        break;
+                }
+            }
             event.append(" Extras=");
             SyncOperation.extrasToStringBuilder(item.extras, event);
 
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 9886a07..e810b1a 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -367,6 +367,7 @@
 import java.util.concurrent.TimeUnit;
 import java.util.concurrent.atomic.AtomicBoolean;
 import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Predicate;
 
 /**
  * Keep track of all those APKs everywhere.
@@ -13942,6 +13943,43 @@
         return false;
     }
 
+    @Override
+    public boolean setSystemAppInstallState(String packageName, boolean installed, int userId) {
+        enforceSystemOrPhoneCaller("setSystemAppInstallState");
+        PackageSetting pkgSetting = mSettings.mPackages.get(packageName);
+        // The target app should always be in system
+        if (pkgSetting == null || !pkgSetting.isSystem()) {
+            return false;
+        }
+        // Check if the install state is the same
+        if (pkgSetting.getInstalled(userId) == installed) {
+            return false;
+        }
+
+        long callingId = Binder.clearCallingIdentity();
+        try {
+            if (installed) {
+                // install the app from uninstalled state
+                installExistingPackageAsUser(
+                        packageName,
+                        userId,
+                        0 /*installFlags*/,
+                        PackageManager.INSTALL_REASON_DEVICE_SETUP);
+                return true;
+            }
+
+            // uninstall the app from installed state
+            deletePackageVersioned(
+                    new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),
+                    new LegacyPackageDeleteObserver(null).getBinder(),
+                    userId,
+                    PackageManager.DELETE_SYSTEM_APP);
+            return true;
+        } finally {
+            Binder.restoreCallingIdentity(callingId);
+        }
+    }
+
     private void sendApplicationHiddenForUser(String packageName, PackageSetting pkgSetting,
             int userId) {
         final PackageRemovedInfo info = new PackageRemovedInfo(this);
@@ -14006,10 +14044,16 @@
     @Override
     public int installExistingPackageAsUser(String packageName, int userId, int installFlags,
             int installReason) {
-        mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES,
-                null);
-        PackageSetting pkgSetting;
         final int callingUid = Binder.getCallingUid();
+        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.INSTALL_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED
+                && mContext.checkCallingOrSelfPermission(
+                        android.Manifest.permission.INSTALL_EXISTING_PACKAGES)
+                != PackageManager.PERMISSION_GRANTED) {
+            throw new SecurityException("Neither user " + callingUid + " nor current process has "
+                    + android.Manifest.permission.INSTALL_PACKAGES + ".");
+        }
+        PackageSetting pkgSetting;
         mPermissionManager.enforceCrossUserPermission(callingUid, userId,
                 true /* requireFullPermission */, true /* checkShell */,
                 "installExistingPackage for user " + userId);
@@ -14258,28 +14302,50 @@
      * @param packageName The package holding {@link Manifest.permission#SUSPEND_APPS} permission
      * @param affectedUser The user for which the changes are taking place.
      */
-    void unsuspendForSuspendingPackage(String packageName, int affectedUser) {
+    void unsuspendForSuspendingPackage(final String packageName, int affectedUser) {
         final int[] userIds = (affectedUser == UserHandle.USER_ALL) ? sUserManager.getUserIds()
                 : new int[] {affectedUser};
         for (int userId : userIds) {
-            List<String> affectedPackages = new ArrayList<>();
-            synchronized (mPackages) {
-                for (PackageSetting ps : mSettings.mPackages.values()) {
-                    final PackageUserState pus = ps.readUserState(userId);
-                    if (pus.suspended && packageName.equals(pus.suspendingPackage)) {
-                        ps.setSuspended(false, null, null, null, null, userId);
-                        affectedPackages.add(ps.name);
-                    }
+            unsuspendForSuspendingPackages(packageName::equals, userId);
+        }
+    }
+
+    /**
+     * Immediately unsuspends any packages in the given users not suspended by the platform or root.
+     * To be called when a profile owner or a device owner is added.
+     *
+     * <p><b>Should not be used on a frequent code path</b> as it flushes state to disk
+     * synchronously
+     *
+     * @param userIds The users for which to unsuspend packages
+     */
+    void unsuspendForNonSystemSuspendingPackages(ArraySet<Integer> userIds) {
+        final int sz = userIds.size();
+        for (int i = 0; i < sz; i++) {
+            unsuspendForSuspendingPackages(
+                    (suspendingPackage) -> !PLATFORM_PACKAGE_NAME.equals(suspendingPackage),
+                    userIds.valueAt(i));
+        }
+    }
+
+    private void unsuspendForSuspendingPackages(Predicate<String> packagePredicate, int userId) {
+        final List<String> affectedPackages = new ArrayList<>();
+        synchronized (mPackages) {
+            for (PackageSetting ps : mSettings.mPackages.values()) {
+                final PackageUserState pus = ps.readUserState(userId);
+                if (pus.suspended && packagePredicate.test(pus.suspendingPackage)) {
+                    ps.setSuspended(false, null, null, null, null, userId);
+                    affectedPackages.add(ps.name);
                 }
             }
-            if (!affectedPackages.isEmpty()) {
-                final String[] packageArray = affectedPackages.toArray(
-                        new String[affectedPackages.size()]);
-                sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId);
-                sendPackagesSuspendedForUser(packageArray, userId, false, null);
-                // Write package restrictions immediately to avoid an inconsistent state.
-                mSettings.writePackageRestrictionsLPr(userId);
-            }
+        }
+        if (!affectedPackages.isEmpty()) {
+            final String[] packageArray = affectedPackages.toArray(
+                    new String[affectedPackages.size()]);
+            sendMyPackageSuspendedOrUnsuspended(packageArray, false, null, userId);
+            sendPackagesSuspendedForUser(packageArray, userId, false, null);
+            // Write package restrictions immediately to avoid an inconsistent state.
+            mSettings.writePackageRestrictionsLPr(userId);
         }
     }
 
@@ -23977,6 +24043,18 @@
                 SparseArray<String> profileOwnerPackages) {
             mProtectedPackages.setDeviceAndProfileOwnerPackages(
                     deviceOwnerUserId, deviceOwnerPackage, profileOwnerPackages);
+
+            final ArraySet<Integer> usersWithPoOrDo = new ArraySet<>();
+            if (deviceOwnerPackage != null) {
+                usersWithPoOrDo.add(deviceOwnerUserId);
+            }
+            final int sz = profileOwnerPackages.size();
+            for (int i = 0; i < sz; i++) {
+                if (profileOwnerPackages.valueAt(i) != null) {
+                    usersWithPoOrDo.add(profileOwnerPackages.keyAt(i));
+                }
+            }
+            unsuspendForNonSystemSuspendingPackages(usersWithPoOrDo);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index 2886126..547ab0e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -557,7 +557,7 @@
         if (cropFile != null) {
             Bitmap bitmap = BitmapFactory.decodeFile(cropFile);
             if (bitmap != null) {
-                colors = WallpaperColors.fromBitmap(bitmap, true /* computeHints */);
+                colors = WallpaperColors.fromBitmap(bitmap);
                 bitmap.recycle();
             }
         }
diff --git a/services/tests/servicestests/AndroidManifest.xml b/services/tests/servicestests/AndroidManifest.xml
index 2ac9df9..a8efe81 100644
--- a/services/tests/servicestests/AndroidManifest.xml
+++ b/services/tests/servicestests/AndroidManifest.xml
@@ -70,7 +70,7 @@
     <uses-sdk android:minSdkVersion="1"
           android:targetSdkVersion="26"/>
 
-    <application>
+    <application android:testOnly="true">
         <uses-library android:name="android.test.runner" />
 
         <service android:name="com.android.server.accounts.TestAccountType1AuthenticatorService"
diff --git a/services/tests/servicestests/AndroidTest.xml b/services/tests/servicestests/AndroidTest.xml
index 8f989df..5ac68d4 100644
--- a/services/tests/servicestests/AndroidTest.xml
+++ b/services/tests/servicestests/AndroidTest.xml
@@ -18,6 +18,7 @@
     <option name="test-suite-tag" value="apct-instrumentation" />
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
+        <option name="install-arg" value="-t" />
         <option name="test-file-name" value="FrameworksServicesTests.apk" />
         <option name="test-file-name" value="JobTestApp.apk" />
         <option name="test-file-name" value="ConnTestApp.apk" />
diff --git a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
index b8922eb..c186e48 100644
--- a/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/SuspendPackagesTest.java
@@ -22,6 +22,7 @@
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
+import static org.junit.Assume.assumeTrue;
 
 import android.app.AppGlobals;
 import android.content.BroadcastReceiver;
@@ -59,6 +60,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.IOException;
 import java.util.Arrays;
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.SynchronousQueue;
@@ -97,6 +99,9 @@
     private AppCommunicationReceiver mAppCommsReceiver;
     private StubbedCallback mTestCallback;
     private UiDevice mUiDevice;
+    private ComponentName mDeviceAdminComponent;
+    private boolean mPoSet;
+    private boolean mDoSet;
 
     private static final class AppCommunicationReceiver extends BroadcastReceiver {
         private Context context;
@@ -163,6 +168,8 @@
         mLauncherApps = (LauncherApps) mContext.getSystemService(Context.LAUNCHER_APPS_SERVICE);
         mReceiverHandler = new Handler(Looper.getMainLooper());
         mUiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation());
+        mDeviceAdminComponent = new ComponentName(mContext,
+                "com.android.server.devicepolicy.DummyDeviceAdmins$Admin1");
         IPackageManager ipm = AppGlobals.getPackageManager();
         try {
             // Otherwise implicit broadcasts will not be delivered.
@@ -469,12 +476,83 @@
                 TEST_APP_PACKAGE_NAME, receivedPackageName);
     }
 
+    private boolean setProfileOwner() throws IOException {
+        final String result = mUiDevice.executeShellCommand("dpm set-profile-owner --user cur "
+                + mDeviceAdminComponent.flattenToString());
+        return mPoSet = result.trim().startsWith("Success");
+    }
+
+    private boolean setDeviceOwner() throws IOException {
+        final String result = mUiDevice.executeShellCommand("dpm set-device-owner --user cur "
+                + mDeviceAdminComponent.flattenToString());
+        return mDoSet = result.trim().startsWith("Success");
+    }
+
+    private void removeProfileOrDeviceOwner() throws IOException {
+        if (mPoSet || mDoSet) {
+            mUiDevice.executeShellCommand("dpm remove-active-admin --user cur "
+                    + mDeviceAdminComponent.flattenToString());
+            mPoSet = mDoSet = false;
+        }
+    }
+
+    @Test
+    public void testCannotSuspendWhenProfileOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        assertTrue("Profile-owner could not be set", setProfileOwner());
+        try {
+            suspendTestPackage(null, null, null);
+            fail("Suspend succeeded. Expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException uex) {
+        }
+    }
+
+    @Test
+    public void testCannotSuspendWhenDeviceOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        assertTrue("Device-owner could not be set", setDeviceOwner());
+        try {
+            suspendTestPackage(null, null, null);
+            fail("Suspend succeeded. Expected UnsupportedOperationException");
+        } catch (UnsupportedOperationException uex) {
+        }
+    }
+
+    @Test
+    public void testPackageUnsuspendedOnAddingDeviceOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
+        mAppCommsReceiver.drainPendingBroadcasts();
+        suspendTestPackage(null, null, null);
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
+        assertTrue("Device-owner could not be set", setDeviceOwner());
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
+    }
+
+    @Test
+    public void testPackageUnsuspendedOnAddingProfileOwner() throws IOException {
+        assumeTrue(mPackageManager.hasSystemFeature(PackageManager.FEATURE_DEVICE_ADMIN));
+        mAppCommsReceiver.register(mReceiverHandler, ACTION_REPORT_MY_PACKAGE_UNSUSPENDED,
+                ACTION_REPORT_MY_PACKAGE_SUSPENDED);
+        mAppCommsReceiver.drainPendingBroadcasts();
+        suspendTestPackage(null, null, null);
+        Intent intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_SUSPENDED, intentFromApp.getAction());
+        assertTrue("Profile-owner could not be set", setProfileOwner());
+        intentFromApp = mAppCommsReceiver.receiveIntentFromApp();
+        assertEquals(ACTION_REPORT_MY_PACKAGE_UNSUSPENDED, intentFromApp.getAction());
+    }
+
     @After
-    public void tearDown() {
+    public void tearDown() throws IOException {
         mAppCommsReceiver.unregister();
         if (mTestCallback != null) {
             mLauncherApps.unregisterCallback(mTestCallback);
         }
+        removeProfileOrDeviceOwner();
         mContext.sendBroadcast(new Intent(ACTION_FINISH_TEST_ACTIVITY)
                 .setPackage(TEST_APP_PACKAGE_NAME));
     }
diff --git a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
index dee2556..8461166 100644
--- a/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
+++ b/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
@@ -218,6 +218,11 @@
                     + "stable_charging_threshold=" + STABLE_CHARGING_THRESHOLD;
         }
 
+        @Override
+        public boolean isDeviceIdleMode() {
+            return false;
+        }
+
         // Internal methods
 
         void setDisplayOn(boolean on) {
diff --git a/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java b/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java
index 4d99b32..9c010a0 100644
--- a/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java
+++ b/services/tests/servicestests/src/com/android/server/wallpaper/WallpaperServiceTests.java
@@ -20,8 +20,6 @@
 import static org.junit.Assert.assertTrue;
 
 import android.app.WallpaperColors;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
 import android.os.Handler;
 import android.os.Message;
 import android.os.SystemClock;
@@ -87,17 +85,4 @@
         assertEquals("OnComputeColors should have been deferred.",
                 0, eventCountdown.getCount());
     }
-
-    @Test
-    public void testFromDrawableTest_doesntComputeHints() {
-        WallpaperColors wallpaperColors = WallpaperColors.fromDrawable(
-                new ColorDrawable(Color.BLACK));
-        assertEquals("WallpaperColors should not support dark theme.", 0,
-                wallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME);
-
-        wallpaperColors = WallpaperColors.fromDrawable(
-                new ColorDrawable(Color.WHITE));
-        assertEquals("WallpaperColors should not support dark text.", 0,
-                wallpaperColors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_TEXT);
-    }
 }
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 3378897..9c62700 100644
--- a/services/usage/java/com/android/server/usage/AppStandbyController.java
+++ b/services/usage/java/com/android/server/usage/AppStandbyController.java
@@ -24,6 +24,8 @@
 import static android.app.usage.UsageStatsManager.REASON_MAIN_USAGE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_PREDICTED_RESTORED;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_ACTIVE_TIMEOUT;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
+import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_EXEMPTED_SYNC_START;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_BACKGROUND;
 import static android.app.usage.UsageStatsManager.REASON_SUB_USAGE_MOVE_TO_FOREGROUND;
@@ -194,8 +196,9 @@
     static final int MSG_ONE_TIME_CHECK_IDLE_STATES = 10;
     /** Check the state of one app: arg1 = userId, arg2 = uid, obj = (String) packageName */
     static final int MSG_CHECK_PACKAGE_IDLE_STATE = 11;
-    static final int MSG_REPORT_EXEMPTED_SYNC_START = 12;
-    static final int MSG_UPDATE_STABLE_CHARGING= 13;
+    static final int MSG_REPORT_EXEMPTED_SYNC_SCHEDULED = 12;
+    static final int MSG_REPORT_EXEMPTED_SYNC_START = 13;
+    static final int MSG_UPDATE_STABLE_CHARGING= 14;
 
     long mCheckIdleIntervalMillis;
     long mAppIdleParoleIntervalMillis;
@@ -213,8 +216,20 @@
     long mPredictionTimeoutMillis;
     /** Maximum time a sync adapter associated with a CP should keep the buckets elevated. */
     long mSyncAdapterTimeoutMillis;
-    /** Maximum time an exempted sync should keep the buckets elevated. */
-    long mExemptedSyncAdapterTimeoutMillis;
+    /**
+     * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
+     * non-doze
+     */
+    long mExemptedSyncScheduledNonDozeTimeoutMillis;
+    /**
+     * Maximum time an exempted sync should keep the buckets elevated, when sync is scheduled in
+     * doze
+     */
+    long mExemptedSyncScheduledDozeTimeoutMillis;
+    /**
+     * Maximum time an exempted sync should keep the buckets elevated, when sync is started.
+     */
+    long mExemptedSyncStartTimeoutMillis;
     /** Maximum time a system interaction should keep the buckets elevated. */
     long mSystemInteractionTimeoutMillis;
     /** The length of time phone must be charging before considered stable enough to run jobs  */
@@ -393,6 +408,37 @@
         }
     }
 
+    void reportExemptedSyncScheduled(String packageName, int userId) {
+        if (!mAppIdleEnabled) return;
+
+        final int bucketToPromote;
+        final int usageReason;
+        final long durationMillis;
+
+        if (!mInjector.isDeviceIdleMode()) {
+            // Not dozing.
+            bucketToPromote = STANDBY_BUCKET_ACTIVE;
+            usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_NON_DOZE;
+            durationMillis = mExemptedSyncScheduledNonDozeTimeoutMillis;
+        } else {
+            // Dozing.
+            bucketToPromote = STANDBY_BUCKET_WORKING_SET;
+            usageReason = REASON_SUB_USAGE_EXEMPTED_SYNC_SCHEDULED_DOZE;
+            durationMillis = mExemptedSyncScheduledDozeTimeoutMillis;
+        }
+
+        final long elapsedRealtime = mInjector.elapsedRealtime();
+
+        synchronized (mAppIdleLock) {
+            AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
+                    bucketToPromote, usageReason,
+                    0,
+                    elapsedRealtime + durationMillis);
+            maybeInformListeners(packageName, userId, elapsedRealtime,
+                    appUsage.currentBucket, appUsage.bucketingReason, false);
+        }
+    }
+
     void reportExemptedSyncStart(String packageName, int userId) {
         if (!mAppIdleEnabled) return;
 
@@ -402,7 +448,7 @@
             AppUsageHistory appUsage = mAppIdleHistory.reportUsage(packageName, userId,
                     STANDBY_BUCKET_ACTIVE, REASON_SUB_USAGE_EXEMPTED_SYNC_START,
                     0,
-                    elapsedRealtime + mExemptedSyncAdapterTimeoutMillis);
+                    elapsedRealtime + mExemptedSyncStartTimeoutMillis);
             maybeInformListeners(packageName, userId, elapsedRealtime,
                     appUsage.currentBucket, appUsage.bucketingReason, false);
         }
@@ -1365,6 +1411,11 @@
                 .sendToTarget();
     }
 
+    void postReportExemptedSyncScheduled(String packageName, int userId) {
+        mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_SCHEDULED, userId, 0, packageName)
+                .sendToTarget();
+    }
+
     void postReportExemptedSyncStart(String packageName, int userId) {
         mHandler.obtainMessage(MSG_REPORT_EXEMPTED_SYNC_START, userId, 0, packageName)
                 .sendToTarget();
@@ -1401,6 +1452,16 @@
         TimeUtils.formatDuration(mAppIdleParoleDurationMillis, pw);
         pw.println();
 
+        pw.print("  mExemptedSyncScheduledNonDozeTimeoutMillis=");
+        TimeUtils.formatDuration(mExemptedSyncScheduledNonDozeTimeoutMillis, pw);
+        pw.println();
+        pw.print("  mExemptedSyncScheduledDozeTimeoutMillis=");
+        TimeUtils.formatDuration(mExemptedSyncScheduledDozeTimeoutMillis, pw);
+        pw.println();
+        pw.print("  mExemptedSyncStartTimeoutMillis=");
+        TimeUtils.formatDuration(mExemptedSyncStartTimeoutMillis, pw);
+        pw.println();
+
         pw.println();
         pw.print("mAppIdleEnabled="); pw.print(mAppIdleEnabled);
         pw.print(" mAppIdleTempParoled="); pw.print(mAppIdleTempParoled);
@@ -1429,6 +1490,7 @@
         private IBatteryStats mBatteryStats;
         private PackageManagerInternal mPackageManagerInternal;
         private DisplayManager mDisplayManager;
+        private PowerManager mPowerManager;
         int mBootPhase;
 
         Injector(Context context, Looper looper) {
@@ -1453,6 +1515,7 @@
                 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
                 mDisplayManager = (DisplayManager) mContext.getSystemService(
                         Context.DISPLAY_SERVICE);
+                mPowerManager = mContext.getSystemService(PowerManager.class);
             }
             mBootPhase = phase;
         }
@@ -1532,6 +1595,11 @@
             return Global.getString(mContext.getContentResolver(),
                     Global.APP_IDLE_CONSTANTS);
         }
+
+        /** Whether the device is in doze or not. */
+        public boolean isDeviceIdleMode() {
+            return mPowerManager.isDeviceIdleMode();
+        }
     }
 
     class AppStandbyHandler extends Handler {
@@ -1595,6 +1663,10 @@
                             mInjector.elapsedRealtime());
                     break;
 
+                case MSG_REPORT_EXEMPTED_SYNC_SCHEDULED:
+                    reportExemptedSyncScheduled((String) msg.obj, msg.arg1);
+                    break;
+
                 case MSG_REPORT_EXEMPTED_SYNC_START:
                     reportExemptedSyncStart((String) msg.obj, msg.arg1);
                     break;
@@ -1684,7 +1756,12 @@
                 "system_update_usage_duration";
         private static final String KEY_PREDICTION_TIMEOUT = "prediction_timeout";
         private static final String KEY_SYNC_ADAPTER_HOLD_DURATION = "sync_adapter_duration";
-        private static final String KEY_EXEMPTED_SYNC_HOLD_DURATION = "exempted_sync_duration";
+        private static final String KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION
+                = "exempted_sync_scheduled_nd_duration";
+        private static final String KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION
+                = "exempted_sync_scheduled_d_duration";
+        private static final String KEY_EXEMPTED_SYNC_START_HOLD_DURATION
+                = "exempted_sync_start_duration";
         private static final String KEY_SYSTEM_INTERACTION_HOLD_DURATION =
                 "system_interaction_duration";
         private static final String KEY_STABLE_CHARGING_THRESHOLD = "stable_charging_threshold";
@@ -1693,7 +1770,9 @@
         public static final long DEFAULT_SYSTEM_UPDATE_TIMEOUT = 2 * ONE_HOUR;
         public static final long DEFAULT_SYSTEM_INTERACTION_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_SYNC_ADAPTER_TIMEOUT = 10 * ONE_MINUTE;
-        public static final long DEFAULT_EXEMPTED_SYNC_TIMEOUT = 10 * ONE_MINUTE;
+        public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT = 10 * ONE_MINUTE;
+        public static final long DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT = 4 * ONE_HOUR;
+        public static final long DEFAULT_EXEMPTED_SYNC_START_TIMEOUT = 10 * ONE_MINUTE;
         public static final long DEFAULT_STABLE_CHARGING_THRESHOLD = 10 * ONE_MINUTE;
 
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -1778,9 +1857,22 @@
                 mSyncAdapterTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYNC_ADAPTER_HOLD_DURATION,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYNC_ADAPTER_TIMEOUT);
-                mExemptedSyncAdapterTimeoutMillis = mParser.getDurationMillis
-                        (KEY_EXEMPTED_SYNC_HOLD_DURATION,
-                                COMPRESS_TIME ? ONE_MINUTE : DEFAULT_EXEMPTED_SYNC_TIMEOUT);
+
+                mExemptedSyncScheduledNonDozeTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_HOLD_DURATION,
+                                COMPRESS_TIME ? (ONE_MINUTE / 2)
+                                        : DEFAULT_EXEMPTED_SYNC_SCHEDULED_NON_DOZE_TIMEOUT);
+
+                mExemptedSyncScheduledDozeTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_SCHEDULED_DOZE_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE
+                                        : DEFAULT_EXEMPTED_SYNC_SCHEDULED_DOZE_TIMEOUT);
+
+                mExemptedSyncStartTimeoutMillis = mParser.getDurationMillis
+                        (KEY_EXEMPTED_SYNC_START_HOLD_DURATION,
+                                COMPRESS_TIME ? ONE_MINUTE
+                                        : DEFAULT_EXEMPTED_SYNC_START_TIMEOUT);
+
                 mSystemInteractionTimeoutMillis = mParser.getDurationMillis
                         (KEY_SYSTEM_INTERACTION_HOLD_DURATION,
                                 COMPRESS_TIME ? ONE_MINUTE : DEFAULT_SYSTEM_INTERACTION_TIMEOUT);
diff --git a/services/usage/java/com/android/server/usage/UsageStatsService.java b/services/usage/java/com/android/server/usage/UsageStatsService.java
index 6311127a..a7d3f78 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -1371,6 +1371,11 @@
         }
 
         @Override
+        public void reportExemptedSyncScheduled(String packageName, int userId) {
+            mAppStandby.postReportExemptedSyncScheduled(packageName, userId);
+        }
+
+        @Override
         public void reportExemptedSyncStart(String packageName, int userId) {
             mAppStandby.postReportExemptedSyncStart(packageName, userId);
         }
diff --git a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
index bcad554..676684c 100644
--- a/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
+++ b/telephony/java/com/android/internal/telephony/CarrierAppUtils.java
@@ -152,9 +152,14 @@
                             && (ai.enabledSetting ==
                             PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                             || ai.enabledSetting ==
-                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED)) {
+                            PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                            || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0)) {
                         Slog.i(TAG, "Update state(" + packageName + "): ENABLED for user "
                                 + userId);
+                        packageManager.setSystemAppInstallState(
+                                packageName,
+                                true /*installed*/,
+                                userId);
                         packageManager.setApplicationEnabledSetting(
                                 packageName,
                                 PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -170,9 +175,14 @@
                             if (associatedApp.enabledSetting ==
                                     PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
                                     || associatedApp.enabledSetting ==
-                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
+                                    PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED
+                                    || (ai.flags & ApplicationInfo.FLAG_INSTALLED) == 0) {
                                 Slog.i(TAG, "Update associated state(" + associatedApp.packageName
                                         + "): ENABLED for user " + userId);
+                                packageManager.setSystemAppInstallState(
+                                        associatedApp.packageName,
+                                        true /*installed*/,
+                                        userId);
                                 packageManager.setApplicationEnabledSetting(
                                         associatedApp.packageName,
                                         PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
@@ -190,15 +200,14 @@
                     // updated we shouldn't touch it.
                     if (!ai.isUpdatedSystemApp()
                             && ai.enabledSetting ==
-                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT) {
+                            PackageManager.COMPONENT_ENABLED_STATE_DEFAULT
+                            && (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0) {
                         Slog.i(TAG, "Update state(" + packageName
                                 + "): DISABLED_UNTIL_USED for user " + userId);
-                        packageManager.setApplicationEnabledSetting(
+                        packageManager.setSystemAppInstallState(
                                 packageName,
-                                PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
-                                0,
-                                userId,
-                                callingPackage);
+                                false /*installed*/,
+                                userId);
                     }
 
                     // Also disable any associated apps for this carrier app if this is the first
@@ -213,13 +222,10 @@
                                     Slog.i(TAG,
                                             "Update associated state(" + associatedApp.packageName
                                                     + "): DISABLED_UNTIL_USED for user " + userId);
-                                    packageManager.setApplicationEnabledSetting(
+                                    packageManager.setSystemAppInstallState(
                                             associatedApp.packageName,
-                                            PackageManager
-                                                    .COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,
-                                            0,
-                                            userId,
-                                            callingPackage);
+                                            false /*installed*/,
+                                            userId);
                                 }
                             }
                         }
@@ -357,7 +363,8 @@
             String packageName) {
         try {
             ApplicationInfo ai = packageManager.getApplicationInfo(packageName,
-                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS, userId);
+                    PackageManager.MATCH_DISABLED_UNTIL_USED_COMPONENTS
+                    | PackageManager.MATCH_HIDDEN_UNTIL_INSTALLED_COMPONENTS, userId);
             if (ai != null && ai.isSystemApp()) {
                 return ai;
             }