Merge "Statsd: ISOLATED_UID_CHANGED out of batterystats"
diff --git a/Android.bp b/Android.bp
index 2de1a6c..77a273c 100644
--- a/Android.bp
+++ b/Android.bp
@@ -766,6 +766,24 @@
     dxflags: ["--core-library"],
 }
 
+// ====  java proto host library  ==============================
+java_library_host {
+    name: "platformprotos",
+    srcs: [
+        "cmds/am/proto/instrumentation_data.proto",
+        "core/proto/**/*.proto",
+        "libs/incident/proto/**/*.proto",
+        "cmds/statsd/src/**/*.proto",
+    ],
+    proto: {
+        include_dirs: ["external/protobuf/src"],
+        type: "full",
+    },
+    errorprone: {
+        javacflags: ["-Xep:MissingOverride:OFF"],  // b/72714520
+    },
+}
+
 // ====  c++ proto device library  ==============================
 cc_library {
     name: "libplatformprotos",
diff --git a/Android.mk b/Android.mk
index c68eb46..031809c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -670,23 +670,6 @@
 
 include $(BUILD_DROIDDOC)
 
-# ====  java proto host library  ==============================
-include $(CLEAR_VARS)
-LOCAL_MODULE := platformprotos
-LOCAL_PROTOC_OPTIMIZE_TYPE := full
-LOCAL_PROTOC_FLAGS := \
-    -Iexternal/protobuf/src
-LOCAL_SOURCE_FILES_ALL_GENERATED := true
-LOCAL_SRC_FILES := \
-    cmds/am/proto/instrumentation_data.proto \
-    cmds/statsd/src/perfetto/perfetto_config.proto \
-    $(call all-proto-files-under, core/proto) \
-    $(call all-proto-files-under, libs/incident/proto) \
-    $(call all-proto-files-under, cmds/statsd/src)
-# b/72714520
-LOCAL_ERROR_PRONE_FLAGS := -Xep:MissingOverride:OFF
-include $(BUILD_HOST_JAVA_LIBRARY)
-
 # ====  java proto device library (for test only)  ==============================
 include $(CLEAR_VARS)
 LOCAL_MODULE := platformprotosnano
diff --git a/api/current.txt b/api/current.txt
index 9d8db31..7787c1bfc 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -70142,7 +70142,7 @@
     method public java.util.regex.Matcher reset();
     method public java.util.regex.Matcher reset(java.lang.CharSequence);
     method public int start();
-    method public int start(int) throws java.lang.IllegalStateException;
+    method public int start(int);
     method public int start(java.lang.String);
     method public java.util.regex.MatchResult toMatchResult();
     method public java.util.regex.Matcher useAnchoringBounds(boolean);
diff --git a/api/system-current.txt b/api/system-current.txt
index 44f0588..6850f8f 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -385,16 +385,16 @@
 
   public final class StatsManager {
     method public void addConfig(long, byte[]) throws android.app.StatsManager.StatsUnavailableException;
-    method public boolean addConfiguration(long, byte[]);
-    method public byte[] getData(long);
-    method public byte[] getMetadata();
+    method public deprecated boolean addConfiguration(long, byte[]);
+    method public deprecated byte[] getData(long);
+    method public deprecated byte[] getMetadata();
     method public byte[] getReports(long) throws android.app.StatsManager.StatsUnavailableException;
     method public byte[] getStatsMetadata() throws android.app.StatsManager.StatsUnavailableException;
     method public void removeConfig(long) throws android.app.StatsManager.StatsUnavailableException;
-    method public boolean removeConfiguration(long);
+    method public deprecated boolean removeConfiguration(long);
     method public void setBroadcastSubscriber(android.app.PendingIntent, long, long) throws android.app.StatsManager.StatsUnavailableException;
-    method public boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
-    method public boolean setDataFetchOperation(long, android.app.PendingIntent);
+    method public deprecated boolean setBroadcastSubscriber(long, long, android.app.PendingIntent);
+    method public deprecated boolean setDataFetchOperation(long, android.app.PendingIntent);
     method public void setFetchReportsOperation(android.app.PendingIntent, long) throws android.app.StatsManager.StatsUnavailableException;
     field public static final java.lang.String ACTION_STATSD_STARTED = "android.app.action.STATSD_STARTED";
     field public static final java.lang.String EXTRA_STATS_BROADCAST_SUBSCRIBER_COOKIES = "android.app.extra.STATS_BROADCAST_SUBSCRIBER_COOKIES";
@@ -538,6 +538,7 @@
     method public long getAvailableRestoreToken(java.lang.String);
     method public android.content.Intent getConfigurationIntent(java.lang.String);
     method public java.lang.String getCurrentTransport();
+    method public android.content.ComponentName getCurrentTransportComponent();
     method public android.content.Intent getDataManagementIntent(java.lang.String);
     method public java.lang.String getDataManagementLabel(java.lang.String);
     method public java.lang.String getDestinationString(java.lang.String);
diff --git a/api/test-current.txt b/api/test-current.txt
index db42186..79a8d44 100644
--- a/api/test-current.txt
+++ b/api/test-current.txt
@@ -244,6 +244,7 @@
 package android.content.pm {
 
   public class ActivityInfo extends android.content.pm.ComponentInfo implements android.os.Parcelable {
+    method public static boolean isTranslucentOrFloating(android.content.res.TypedArray);
     field public static final int RESIZE_MODE_RESIZEABLE = 2; // 0x2
   }
 
@@ -1332,6 +1333,7 @@
 
   public class KeyEvent extends android.view.InputEvent implements android.os.Parcelable {
     method public static java.lang.String actionToString(int);
+    field public static final int LAST_KEYCODE = 285; // 0x11d
   }
 
   public final class KeyboardShortcutGroup implements android.os.Parcelable {
diff --git a/cmds/input/src/com/android/commands/input/Input.java b/cmds/input/src/com/android/commands/input/Input.java
index d3ec320..74edffb 100644
--- a/cmds/input/src/com/android/commands/input/Input.java
+++ b/cmds/input/src/com/android/commands/input/Input.java
@@ -91,9 +91,6 @@
                     if (args.length > start) {
                         for (int i = start; i < args.length; i++) {
                             int keyCode = KeyEvent.keyCodeFromString(args[i]);
-                            if (keyCode == KeyEvent.KEYCODE_UNKNOWN) {
-                                keyCode = KeyEvent.keyCodeFromString("KEYCODE_" + args[i]);
-                            }
                             sendKeyEvent(inputSource, keyCode, longpress);
                         }
                         return;
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/cmds/screencap/screencap.cpp b/cmds/screencap/screencap.cpp
index 3172281..b11e843 100644
--- a/cmds/screencap/screencap.cpp
+++ b/cmds/screencap/screencap.cpp
@@ -182,8 +182,7 @@
     sp<IBinder> display = SurfaceComposerClient::getBuiltInDisplay(displayId);
     if (display == NULL) {
         fprintf(stderr, "Unable to get handle for display %d\n", displayId);
-        // b/36066697: Avoid running static destructors.
-        _exit(1);
+        return 1;
     }
 
     Vector<DisplayInfo> configs;
@@ -192,8 +191,7 @@
     if (static_cast<size_t>(activeConfig) >= configs.size()) {
         fprintf(stderr, "Active config %d not inside configs (size %zu)\n",
                 activeConfig, configs.size());
-        // b/36066697: Avoid running static destructors.
-        _exit(1);
+        return 1;
     }
     uint8_t displayOrientation = configs[activeConfig].orientation;
     uint32_t captureOrientation = ORIENTATION_MAP[displayOrientation];
@@ -204,14 +202,14 @@
             &outBuffer);
     if (result != NO_ERROR) {
         close(fd);
-        _exit(1);
+        return 1;
     }
 
     result = outBuffer->lock(GraphicBuffer::USAGE_SW_READ_OFTEN, &base);
 
     if (base == NULL) {
         close(fd);
-        _exit(1);
+        return 1;
     }
 
     w = outBuffer->getWidth();
@@ -256,6 +254,5 @@
         munmap((void *)mapbase, mapsize);
     }
 
-    // b/36066697: Avoid running static destructors.
-    _exit(0);
+    return 0;
 }
\ No newline at end of file
diff --git a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
index 218d52a..79bed52 100644
--- a/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
+++ b/cmds/statsd/tests/anomaly/AnomalyTracker_test.cpp
@@ -305,10 +305,10 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyB), 2LL);
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
     EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 16, bucket16, {keyB}, {keyA, keyC, keyD}));
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
     detectAndDeclareAnomalies(anomalyTracker, 16, bucket16, eventTimestamp2);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 15L);
     checkRefractoryTimes(anomalyTracker, eventTimestamp2, refractoryPeriodSec,
             {{keyA, -1}, {keyB, eventTimestamp2}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
@@ -366,7 +366,7 @@
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyC), 1LL);
     EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 25, bucket25, {}, {keyA, keyB, keyC, keyD}));
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 24L);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     detectAndDeclareAnomalies(anomalyTracker, 25, bucket25, eventTimestamp5);
     checkRefractoryTimes(anomalyTracker, eventTimestamp5, refractoryPeriodSec,
             {{keyA, -1}, {keyB, eventTimestamp4}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
@@ -374,14 +374,14 @@
     // Add past bucket #25
     anomalyTracker.addPastBucket(bucket25, 25);
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 25L);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 1UL);
     EXPECT_EQ(anomalyTracker.getSumOverPastBuckets(keyD), 1LL);
     EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {},
             {keyA, keyB, keyC, keyD, keyE}));
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
             {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, -1}});
 
@@ -390,9 +390,9 @@
     EXPECT_TRUE(detectAnomaliesPass(anomalyTracker, 28, bucket28, {keyE},
             {keyA, keyB, keyC, keyD}));
     EXPECT_EQ(anomalyTracker.mMostRecentBucketNum, 27L);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     detectAndDeclareAnomalies(anomalyTracker, 28, bucket28, eventTimestamp6 + 7);
-    // TODO: after detectAnomaly fix: EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
+    EXPECT_EQ(anomalyTracker.mSumOverPastBuckets.size(), 0UL);
     checkRefractoryTimes(anomalyTracker, eventTimestamp6, refractoryPeriodSec,
             {{keyA, -1}, {keyB, -1}, {keyC, -1}, {keyD, -1}, {keyE, eventTimestamp6 + 7}});
 }
diff --git a/config/hiddenapi-light-greylist.txt b/config/hiddenapi-light-greylist.txt
index f352e5f..b04d0f9 100644
--- a/config/hiddenapi-light-greylist.txt
+++ b/config/hiddenapi-light-greylist.txt
@@ -737,6 +737,7 @@
 Landroid/app/IWallpaperManager;->getWallpaper(Ljava/lang/String;Landroid/app/IWallpaperManagerCallback;ILandroid/os/Bundle;I)Landroid/os/ParcelFileDescriptor;
 Landroid/app/IWallpaperManager;->getWallpaperInfo(I)Landroid/app/WallpaperInfo;
 Landroid/app/IWallpaperManager;->getWidthHint()I
+Landroid/app/IWallpaperManager;->hasNamedWallpaper(Ljava/lang/String;)Z
 Landroid/app/IWallpaperManager;->setWallpaperComponent(Landroid/content/ComponentName;)V
 Landroid/app/IWallpaperManagerCallback$Stub;-><init>()V
 Landroid/app/IWallpaperManagerCallback;->onWallpaperChanged()V
@@ -919,6 +920,7 @@
 Landroid/app/ServiceConnectionLeaked;-><init>(Ljava/lang/String;)V
 Landroid/app/SharedPreferencesImpl;-><init>(Ljava/io/File;I)V
 Landroid/app/SharedPreferencesImpl;->mFile:Ljava/io/File;
+Landroid/app/SharedPreferencesImpl;->startLoadFromDisk()V
 Landroid/app/SharedPreferencesImpl;->startReloadIfChangedUnexpectedly()V
 Landroid/app/StatusBarManager;-><init>(Landroid/content/Context;)V
 Landroid/app/StatusBarManager;->collapsePanels()V
@@ -1029,6 +1031,7 @@
 Landroid/bluetooth/BluetoothA2dp;->setOptionalCodecsEnabled(Landroid/bluetooth/BluetoothDevice;I)V
 Landroid/bluetooth/BluetoothA2dp;->stateToString(I)Ljava/lang/String;
 Landroid/bluetooth/BluetoothA2dp;->supportsOptionalCodecs(Landroid/bluetooth/BluetoothDevice;)I
+Landroid/bluetooth/BluetoothA2dpSink;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/BluetoothAdapter;->disable(Z)Z
 Landroid/bluetooth/BluetoothAdapter;->factoryReset()Z
 Landroid/bluetooth/BluetoothAdapter;->getBluetoothManager()Landroid/bluetooth/IBluetoothManager;
@@ -1104,6 +1107,7 @@
 Landroid/bluetooth/BluetoothDevice;->EXTRA_SDP_SEARCH_STATUS:Ljava/lang/String;
 Landroid/bluetooth/BluetoothDevice;->getAlias()Ljava/lang/String;
 Landroid/bluetooth/BluetoothDevice;->getAliasName()Ljava/lang/String;
+Landroid/bluetooth/BluetoothDevice;->getBatteryLevel()I
 Landroid/bluetooth/BluetoothDevice;->getMessageAccessPermission()I
 Landroid/bluetooth/BluetoothDevice;->getPhonebookAccessPermission()I
 Landroid/bluetooth/BluetoothDevice;->getService()Landroid/bluetooth/IBluetooth;
@@ -1164,6 +1168,7 @@
 Landroid/bluetooth/BluetoothHearingAid;->ACTION_ACTIVE_DEVICE_CHANGED:Ljava/lang/String;
 Landroid/bluetooth/BluetoothHearingAid;->getActiveDevices()Ljava/util/List;
 Landroid/bluetooth/BluetoothHearingAid;->setActiveDevice(Landroid/bluetooth/BluetoothDevice;)Z
+Landroid/bluetooth/BluetoothMap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/BluetoothMapClient;->sendMessage(Landroid/bluetooth/BluetoothDevice;[Landroid/net/Uri;Ljava/lang/String;Landroid/app/PendingIntent;Landroid/app/PendingIntent;)Z
 Landroid/bluetooth/BluetoothPan;-><init>(Landroid/content/Context;Landroid/bluetooth/BluetoothProfile$ServiceListener;)V
 Landroid/bluetooth/BluetoothPan;->close()V
@@ -1175,11 +1180,13 @@
 Landroid/bluetooth/BluetoothPan;->isValidDevice(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/BluetoothPan;->log(Ljava/lang/String;)V
 Landroid/bluetooth/BluetoothPan;->setBluetoothTethering(Z)V
+Landroid/bluetooth/BluetoothPbap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/BluetoothProfile;->A2DP_SINK:I
 Landroid/bluetooth/BluetoothProfile;->AVRCP_CONTROLLER:I
 Landroid/bluetooth/BluetoothProfile;->PAN:I
 Landroid/bluetooth/BluetoothProfile;->PRIORITY_AUTO_CONNECT:I
 Landroid/bluetooth/BluetoothProfile;->PRIORITY_UNDEFINED:I
+Landroid/bluetooth/BluetoothSap;->disconnect(Landroid/bluetooth/BluetoothDevice;)Z
 Landroid/bluetooth/BluetoothServerSocket;->mSocket:Landroid/bluetooth/BluetoothSocket;
 Landroid/bluetooth/BluetoothSocket;->EADDRINUSE:I
 Landroid/bluetooth/BluetoothSocket;->flush()V
@@ -1311,6 +1318,7 @@
 Landroid/content/Context;->checkPermission(Ljava/lang/String;IILandroid/os/IBinder;)I
 Landroid/content/Context;->COUNTRY_DETECTOR:Ljava/lang/String;
 Landroid/content/Context;->createApplicationContext(Landroid/content/pm/ApplicationInfo;I)Landroid/content/Context;
+Landroid/content/Context;->ETHERNET_SERVICE:Ljava/lang/String;
 Landroid/content/Context;->getBasePackageName()Ljava/lang/String;
 Landroid/content/Context;->getDisplay()Landroid/view/Display;
 Landroid/content/Context;->getSharedPrefsFile(Ljava/lang/String;)Ljava/io/File;
@@ -1389,6 +1397,7 @@
 Landroid/content/ISyncAdapter$Stub;-><init>()V
 Landroid/content/ISyncAdapter$Stub;->asInterface(Landroid/os/IBinder;)Landroid/content/ISyncAdapter;
 Landroid/content/ISyncAdapter;->cancelSync(Landroid/content/ISyncContext;)V
+Landroid/content/ISyncAdapter;->onUnsyncableAccount(Landroid/content/ISyncAdapterUnsyncableAccountCallback;)V
 Landroid/content/ISyncAdapter;->startSync(Landroid/content/ISyncContext;Ljava/lang/String;Landroid/accounts/Account;Landroid/os/Bundle;)V
 Landroid/content/ISyncContext$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/ISyncContext$Stub$Proxy;->mRemote:Landroid/os/IBinder;
@@ -1434,6 +1443,8 @@
 Landroid/content/pm/ApplicationInfo;->secondaryCpuAbi:Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->secondaryNativeLibraryDir:Ljava/lang/String;
 Landroid/content/pm/ApplicationInfo;->versionCode:I
+Landroid/content/pm/BaseParceledListSlice;->getList()Ljava/util/List;
+Landroid/content/pm/BaseParceledListSlice;->writeParcelableCreator(Ljava/lang/Object;Landroid/os/Parcel;)V
 Landroid/content/pm/ComponentInfo;->getComponentName()Landroid/content/ComponentName;
 Landroid/content/pm/IPackageDataObserver$Stub$Proxy;-><init>(Landroid/os/IBinder;)V
 Landroid/content/pm/IPackageDataObserver$Stub$Proxy;->mRemote:Landroid/os/IBinder;
@@ -1707,6 +1718,8 @@
 Landroid/content/pm/PackageStats;->userHandle:I
 Landroid/content/pm/PackageUserState;-><init>()V
 Landroid/content/pm/ParceledListSlice;-><init>(Ljava/util/List;)V
+Landroid/content/pm/ParceledListSlice;->CREATOR:Landroid/os/Parcelable$ClassLoaderCreator;
+Landroid/content/pm/ParceledListSlice;->writeParcelableCreator(Landroid/os/Parcelable;Landroid/os/Parcel;)V
 Landroid/content/pm/PermissionInfo;->protectionToString(I)Ljava/lang/String;
 Landroid/content/pm/RegisteredServicesCache$ServiceInfo;->componentName:Landroid/content/ComponentName;
 Landroid/content/pm/RegisteredServicesCache$ServiceInfo;->type:Ljava/lang/Object;
@@ -2183,10 +2196,13 @@
 Landroid/graphics/drawable/VectorDrawable;->mTintFilter:Landroid/graphics/PorterDuffColorFilter;
 Landroid/graphics/drawable/VectorDrawable;->setAllowCaching(Z)V
 Landroid/graphics/FontFamily;-><init>()V
+Landroid/graphics/FontFamily;-><init>([Ljava/lang/String;I)V
 Landroid/graphics/FontFamily;->abortCreation()V
 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
@@ -2260,6 +2276,7 @@
 Landroid/graphics/TableMaskFilter;->CreateClipTable(II)Landroid/graphics/TableMaskFilter;
 Landroid/graphics/TemporaryBuffer;->obtain(I)[C
 Landroid/graphics/TemporaryBuffer;->recycle([C)V
+Landroid/graphics/Typeface;-><init>(J)V
 Landroid/graphics/Typeface;->createFromFamilies([Landroid/graphics/FontFamily;)Landroid/graphics/Typeface;
 Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;II)Landroid/graphics/Typeface;
 Landroid/graphics/Typeface;->createFromFamiliesWithDefault([Landroid/graphics/FontFamily;Ljava/lang/String;II)Landroid/graphics/Typeface;
@@ -2269,6 +2286,7 @@
 Landroid/graphics/Typeface;->native_instance:J
 Landroid/graphics/Typeface;->sDefaults:[Landroid/graphics/Typeface;
 Landroid/graphics/Typeface;->setDefault(Landroid/graphics/Typeface;)V
+Landroid/graphics/Typeface;->sSystemFallbackMap:Ljava/util/Map;
 Landroid/graphics/Typeface;->sSystemFontMap:Ljava/util/Map;
 Landroid/graphics/Xfermode;->porterDuffMode:I
 Landroid/hardware/biometrics/BiometricConstants;->BIOMETRIC_ACQUIRED_GOOD:I
@@ -2322,6 +2340,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;
@@ -2378,6 +2397,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;
@@ -3220,6 +3242,14 @@
 Landroid/net/ConnectivityManager;->TYPE_PROXY:I
 Landroid/net/ConnectivityManager;->TYPE_WIFI_P2P:I
 Landroid/net/ConnectivityManager;->unregisterNetworkFactory(Landroid/os/Messenger;)V
+Landroid/net/EthernetManager$Listener;->onAvailabilityChanged(Ljava/lang/String;Z)V
+Landroid/net/EthernetManager;->addListener(Landroid/net/EthernetManager$Listener;)V
+Landroid/net/EthernetManager;->getAvailableInterfaces()[Ljava/lang/String;
+Landroid/net/EthernetManager;->getConfiguration(Ljava/lang/String;)Landroid/net/IpConfiguration;
+Landroid/net/EthernetManager;->isAvailable()Z
+Landroid/net/EthernetManager;->isAvailable(Ljava/lang/String;)Z
+Landroid/net/EthernetManager;->removeListener(Landroid/net/EthernetManager$Listener;)V
+Landroid/net/EthernetManager;->setConfiguration(Ljava/lang/String;Landroid/net/IpConfiguration;)V
 Landroid/net/http/SslCertificate;->getDigest(Ljava/security/cert/X509Certificate;Ljava/lang/String;)Ljava/lang/String;
 Landroid/net/http/SslCertificate;->getSerialNumber(Ljava/security/cert/X509Certificate;)Ljava/lang/String;
 Landroid/net/http/SslCertificate;->inflateCertificateView(Landroid/content/Context;)Landroid/view/View;
@@ -3716,6 +3746,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;
@@ -3750,12 +3781,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
@@ -4108,6 +4147,7 @@
 Landroid/os/storage/StorageManager;->getVolumes()Ljava/util/List;
 Landroid/os/storage/StorageManager;->getVolumeState(Ljava/lang/String;)Ljava/lang/String;
 Landroid/os/storage/StorageManager;->isFileEncryptedNativeOnly()Z
+Landroid/os/storage/StorageManager;->isUsbMassStorageConnected()Z
 Landroid/os/storage/StorageManager;->isUsbMassStorageEnabled()Z
 Landroid/os/storage/StorageManager;->partitionPublic(Ljava/lang/String;)V
 Landroid/os/storage/StorageManager;->unmount(Ljava/lang/String;)V
@@ -4510,6 +4550,7 @@
 Landroid/provider/Settings$System;->LOCKSCREEN_SOUNDS_ENABLED:Ljava/lang/String;
 Landroid/provider/Settings$System;->LOCK_SOUND:Ljava/lang/String;
 Landroid/provider/Settings$System;->MASTER_MONO:Ljava/lang/String;
+Landroid/provider/Settings$System;->NOTIFICATION_LIGHT_PULSE:Ljava/lang/String;
 Landroid/provider/Settings$System;->POINTER_LOCATION:Ljava/lang/String;
 Landroid/provider/Settings$System;->POINTER_SPEED:Ljava/lang/String;
 Landroid/provider/Settings$System;->PRIVATE_SETTINGS:Ljava/util/Set;
@@ -5036,6 +5077,7 @@
 Landroid/service/wallpaper/WallpaperService$Engine;->mPendingXOffset:F
 Landroid/service/wallpaper/WallpaperService$Engine;->setFixedSizeAllowed(Z)V
 Landroid/service/wallpaper/WallpaperService;->MSG_WINDOW_RESIZED:I
+Landroid/speech/IRecognitionListener;->onEvent(ILandroid/os/Bundle;)V
 Landroid/speech/tts/TextToSpeech;->getCurrentEngine()Ljava/lang/String;
 Landroid/speech/tts/TextToSpeech;->mConnectingServiceConnection:Landroid/speech/tts/TextToSpeech$Connection;
 Landroid/speech/tts/TextToSpeech;->mCurrentEngine:Ljava/lang/String;
@@ -5211,6 +5253,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
@@ -5352,6 +5395,7 @@
 Landroid/telephony/SmsMessage;->setSubId(I)V
 Landroid/telephony/SmsMessage;->useCdmaFormatForMoSms()Z
 Landroid/telephony/SmsMessage;->useCdmaFormatForMoSms(I)Z
+Landroid/telephony/SubscriptionInfo;->getNameSource()I
 Landroid/telephony/SubscriptionManager;-><init>(Landroid/content/Context;)V
 Landroid/telephony/SubscriptionManager;->CONTENT_URI:Landroid/net/Uri;
 Landroid/telephony/SubscriptionManager;->DEFAULT_SUBSCRIPTION_ID:I
@@ -5369,6 +5413,7 @@
 Landroid/telephony/SubscriptionManager;->setDataRoaming(II)I
 Landroid/telephony/SubscriptionManager;->setDefaultDataSubId(I)V
 Landroid/telephony/SubscriptionManager;->setDefaultSmsSubId(I)V
+Landroid/telephony/SubscriptionManager;->setDisplayNumber(Ljava/lang/String;I)I
 Landroid/telephony/TelephonyManager$MultiSimVariants;->TSTS:Landroid/telephony/TelephonyManager$MultiSimVariants;
 Landroid/telephony/TelephonyManager$MultiSimVariants;->UNKNOWN:Landroid/telephony/TelephonyManager$MultiSimVariants;
 Landroid/telephony/TelephonyManager$MultiSimVariants;->values()[Landroid/telephony/TelephonyManager$MultiSimVariants;
@@ -5385,6 +5430,8 @@
 Landroid/telephony/TelephonyManager;->getDeviceSoftwareVersion(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getGroupIdLevel1(I)Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getIccAuthentication(IIILjava/lang/String;)Ljava/lang/String;
+Landroid/telephony/TelephonyManager;->getImsConfig(II)Landroid/telephony/ims/aidl/IImsConfig;
+Landroid/telephony/TelephonyManager;->getImsRegistration(II)Landroid/telephony/ims/aidl/IImsRegistration;
 Landroid/telephony/TelephonyManager;->getIsimImpi()Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getIsimImpu()[Ljava/lang/String;
 Landroid/telephony/TelephonyManager;->getIsimPcscf()[Ljava/lang/String;
@@ -5467,6 +5514,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
@@ -7329,6 +7384,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
@@ -8103,6 +8159,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
@@ -8778,7 +8835,6 @@
 Ljava/util/ArrayList;->elementData:[Ljava/lang/Object;
 Ljava/util/ArrayList;->size:I
 Ljava/util/Arrays$ArrayList;->a:[Ljava/lang/Object;
-Ljava/util/Arrays;->checkOffsetAndCount(III)V
 Ljava/util/Arrays;->deepToString([Ljava/lang/Object;Ljava/lang/StringBuilder;Ljava/util/Set;)V
 Ljava/util/Calendar;->zone:Ljava/util/TimeZone;
 Ljava/util/Collections$EmptyList;-><init>()V
@@ -8926,6 +8982,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/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 494ea39..37bf21a 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -939,7 +939,8 @@
         }
 
         public void setHttpProxy(String host, String port, String exclList, Uri pacFileUrl) {
-            final ConnectivityManager cm = ConnectivityManager.from(getSystemContext());
+            final ConnectivityManager cm = ConnectivityManager.from(
+                    getApplication() != null ? getApplication() : getSystemContext());
             final Network network = cm.getBoundNetworkForProcess();
             if (network != null) {
                 Proxy.setHttpProxySystemProperty(cm.getDefaultProxy());
diff --git a/core/java/android/app/AppOpsManager.java b/core/java/android/app/AppOpsManager.java
index 7ddf006..973ca12 100644
--- a/core/java/android/app/AppOpsManager.java
+++ b/core/java/android/app/AppOpsManager.java
@@ -1557,6 +1557,7 @@
         private final long[] mRejectTimes;
         private final int mDuration;
         private final int mProxyUid;
+        private final boolean mRunning;
         private final String mProxyPackageName;
 
         public OpEntry(int op, int mode, long time, long rejectTime, int duration,
@@ -1568,12 +1569,13 @@
             mTimes[0] = time;
             mRejectTimes[0] = rejectTime;
             mDuration = duration;
+            mRunning = duration == -1;
             mProxyUid = proxyUid;
             mProxyPackageName = proxyPackage;
         }
 
         public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
-                int proxyUid, String proxyPackage) {
+                boolean running, int proxyUid, String proxyPackage) {
             mOp = op;
             mMode = mode;
             mTimes = new long[_NUM_UID_STATE];
@@ -1581,10 +1583,16 @@
             System.arraycopy(times, 0, mTimes, 0, _NUM_UID_STATE);
             System.arraycopy(rejectTimes, 0, mRejectTimes, 0, _NUM_UID_STATE);
             mDuration = duration;
+            mRunning = running;
             mProxyUid = proxyUid;
             mProxyPackageName = proxyPackage;
         }
 
+        public OpEntry(int op, int mode, long[] times, long[] rejectTimes, int duration,
+                int proxyUid, String proxyPackage) {
+            this(op, mode, times, rejectTimes, duration, duration == -1, proxyUid, proxyPackage);
+        }
+
         public int getOp() {
             return mOp;
         }
@@ -1634,7 +1642,7 @@
         }
 
         public boolean isRunning() {
-            return mDuration == -1;
+            return mRunning;
         }
 
         public int getDuration() {
@@ -1661,6 +1669,7 @@
             dest.writeLongArray(mTimes);
             dest.writeLongArray(mRejectTimes);
             dest.writeInt(mDuration);
+            dest.writeBoolean(mRunning);
             dest.writeInt(mProxyUid);
             dest.writeString(mProxyPackageName);
         }
@@ -1671,6 +1680,7 @@
             mTimes = source.createLongArray();
             mRejectTimes = source.createLongArray();
             mDuration = source.readInt();
+            mRunning = source.readBoolean();
             mProxyUid = source.readInt();
             mProxyPackageName = source.readString();
         }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 8f0617b..d2338f8 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4924,7 +4924,8 @@
 
             CharSequence[] replyText = mN.extras.getCharSequenceArray(EXTRA_REMOTE_INPUT_HISTORY);
             if (!p.ambient && validRemoteInput && replyText != null
-                    && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])) {
+                    && replyText.length > 0 && !TextUtils.isEmpty(replyText[0])
+                    && p.maxRemoteInputHistory > 0) {
                 boolean showSpinner = mN.extras.getBoolean(EXTRA_SHOW_REMOTE_INPUT_SPINNER);
                 big.setViewVisibility(R.id.notification_material_reply_container, View.VISIBLE);
                 big.setViewVisibility(R.id.notification_material_reply_text_1_container,
@@ -4939,13 +4940,15 @@
                         ColorStateList.valueOf(
                                 isColorized() ? getPrimaryTextColor() : resolveContrastColor()));
 
-                if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])) {
+                if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1])
+                        && p.maxRemoteInputHistory > 1) {
                     big.setViewVisibility(R.id.notification_material_reply_text_2, View.VISIBLE);
                     big.setTextViewText(R.id.notification_material_reply_text_2,
                             processTextSpans(replyText[1]));
                     setTextViewColorSecondary(big, R.id.notification_material_reply_text_2);
 
-                    if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])) {
+                    if (replyText.length > 2 && !TextUtils.isEmpty(replyText[2])
+                            && p.maxRemoteInputHistory > 2) {
                         big.setViewVisibility(
                                 R.id.notification_material_reply_text_3, View.VISIBLE);
                         big.setTextViewText(R.id.notification_material_reply_text_3,
@@ -5108,7 +5111,13 @@
                 return null;
             }
 
-            return applyStandardTemplateWithActions(getBigBaseLayoutResource(), null /* result */);
+            // We only want at most a single remote input history to be shown here, otherwise
+            // the content would become squished.
+            StandardTemplateParams p = mParams.reset().fillTextsFrom(this)
+                    .setMaxRemoteInputHistory(1);
+            return applyStandardTemplateWithActions(getBigBaseLayoutResource(),
+                    p,
+                    null /* result */);
         }
 
         /**
@@ -5977,6 +5986,12 @@
      * object.
      */
     public static abstract class Style {
+
+        /**
+         * The number of items allowed simulatanously in the remote input history.
+         * @hide
+         */
+        static final int MAX_REMOTE_INPUT_HISTORY_LINES = 3;
         private CharSequence mBigContentTitle;
 
         /**
@@ -6588,22 +6603,33 @@
      * Helper class for generating large-format notifications that include multiple back-and-forth
      * messages of varying types between any number of people.
      *
-     * <br>
+     * <p>
      * If the platform does not provide large-format notifications, this method has no effect. The
      * user will always see the normal notification view.
-     * <br>
-     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior, like
-     * so:
+     *
+     * <p>
+     * If the app is targeting Android P and above, it is required to use the {@link Person}
+     * class in order to get an optimal rendering of the notification and its avatars. For
+     * conversations involving multiple people, the app should also make sure that it marks the
+     * conversation as a group with {@link #setGroupConversation(boolean)}.
+     *
+     * <p>
+     * This class is a "rebuilder": It attaches to a Builder object and modifies its behavior.
+     * Here's an example of how this may be used:
      * <pre class="prettyprint">
      *
+     * Person user = new Person.Builder().setIcon(userIcon).setName(userName).build();
+     * MessagingStyle style = new MessagingStyle(user)
+     *      .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getPerson())
+     *      .addMessage(messages[2].getText(), messages[2].getTime(), messages[2].getPerson())
+     *      .setGroupConversation(hasMultiplePeople());
+     *
      * Notification noti = new Notification.Builder()
-     *     .setContentTitle(&quot;2 new messages wtih &quot; + sender.toString())
+     *     .setContentTitle(&quot;2 new messages with &quot; + sender.toString())
      *     .setContentText(subject)
      *     .setSmallIcon(R.drawable.new_message)
      *     .setLargeIcon(aBitmap)
-     *     .setStyle(new Notification.MessagingStyle(resources.getString(R.string.reply_name))
-     *         .addMessage(messages[0].getText(), messages[0].getTime(), messages[0].getSender())
-     *         .addMessage(messages[1].getText(), messages[1].getTime(), messages[1].getSender()))
+     *     .setStyle(style)
      *     .build();
      * </pre>
      */
@@ -6813,7 +6839,9 @@
         }
 
         /**
-         * Sets whether this conversation notification represents a group.
+         * Sets whether this conversation notification represents a group. If the app is targeting
+         * Android P, this is required if the app wants to display the largeIcon set with
+         * {@link Notification.Builder#setLargeIcon(Bitmap)}, otherwise it will be hidden.
          *
          * @param isGroupConversation {@code true} if the conversation represents a group,
          * {@code false} otherwise.
@@ -7035,12 +7063,21 @@
             CharSequence conversationTitle = !TextUtils.isEmpty(super.mBigContentTitle)
                     ? super.mBigContentTitle
                     : mConversationTitle;
-            boolean isOneToOne = TextUtils.isEmpty(conversationTitle);
+            boolean atLeastP = mBuilder.mContext.getApplicationInfo().targetSdkVersion
+                    >= Build.VERSION_CODES.P;
+            boolean isOneToOne;
             CharSequence nameReplacement = null;
-            if (hasOnlyWhiteSpaceSenders()) {
-                isOneToOne = true;
-                nameReplacement = conversationTitle;
-                conversationTitle = null;
+            Icon avatarReplacement = null;
+            if (!atLeastP) {
+                isOneToOne = TextUtils.isEmpty(conversationTitle);
+                avatarReplacement = mBuilder.mN.mLargeIcon;
+                if (hasOnlyWhiteSpaceSenders()) {
+                    isOneToOne = true;
+                    nameReplacement = conversationTitle;
+                    conversationTitle = null;
+                }
+            } else {
+                isOneToOne = !isGroupConversation();
             }
             TemplateBindResult bindResult = new TemplateBindResult();
             RemoteViews contentView = mBuilder.applyStandardTemplateWithActions(
@@ -7063,8 +7100,8 @@
                     mBuilder.getSecondaryTextColor());
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setDisplayImagesAtEnd",
                     displayImagesAtEnd);
-            contentView.setIcon(R.id.status_bar_latest_event_content, "setLargeIcon",
-                    mBuilder.mN.mLargeIcon);
+            contentView.setIcon(R.id.status_bar_latest_event_content, "setAvatarReplacement",
+                    avatarReplacement);
             contentView.setCharSequence(R.id.status_bar_latest_event_content, "setNameReplacement",
                     nameReplacement);
             contentView.setBoolean(R.id.status_bar_latest_event_content, "setIsOneToOne",
@@ -7378,7 +7415,14 @@
                 return messages;
             }
 
-            static Message getMessageFromBundle(Bundle bundle) {
+            /**
+             * @return The message that is stored in the bundle or null if the message couldn't be
+             * resolved.
+             *
+             * @hide
+             */
+            @Nullable
+            public static Message getMessageFromBundle(Bundle bundle) {
                 try {
                     if (!bundle.containsKey(KEY_TEXT) || !bundle.containsKey(KEY_TIMESTAMP)) {
                         return null;
@@ -7436,6 +7480,11 @@
      * @see Notification#bigContentView
      */
     public static class InboxStyle extends Style {
+
+        /**
+         * The number of lines of remote input history allowed until we start reducing lines.
+         */
+        private static final int NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION = 1;
         private ArrayList<CharSequence> mTexts = new ArrayList<CharSequence>(5);
 
         public InboxStyle() {
@@ -7535,6 +7584,28 @@
             if (mBuilder.mActions.size() > 0) {
                 maxRows--;
             }
+            CharSequence[] remoteInputHistory = mBuilder.mN.extras.getCharSequenceArray(
+                    EXTRA_REMOTE_INPUT_HISTORY);
+            if (remoteInputHistory != null
+                    && remoteInputHistory.length > NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION) {
+                // Let's remove some messages to make room for the remote input history.
+                // 1 is always able to fit, but let's remove them if they are 2 or 3
+                int numRemoteInputs = Math.min(remoteInputHistory.length,
+                        MAX_REMOTE_INPUT_HISTORY_LINES);
+                int totalNumRows = mTexts.size() + numRemoteInputs
+                        - NUMBER_OF_HISTORY_ALLOWED_UNTIL_REDUCTION;
+                if (totalNumRows > maxRows) {
+                    int overflow = totalNumRows - maxRows;
+                    if (mTexts.size() > maxRows) {
+                        // Heuristic: if the Texts don't fit anyway, we'll rather drop the last
+                        // few messages, even with the remote input
+                        maxRows -= overflow;
+                    } else  {
+                        // otherwise we drop the first messages
+                        i = overflow;
+                    }
+                }
+            }
             while (i < mTexts.size() && i < maxRows) {
                 CharSequence str = mTexts.get(i);
                 if (!TextUtils.isEmpty(str)) {
@@ -9605,6 +9676,7 @@
         CharSequence title;
         CharSequence text;
         CharSequence headerTextSecondary;
+        int maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
         boolean hideLargeIcon;
         boolean hideReplyIcon;
 
@@ -9614,6 +9686,7 @@
             title = null;
             text = null;
             headerTextSecondary = null;
+            maxRemoteInputHistory = Style.MAX_REMOTE_INPUT_HISTORY_LINES;
             return this;
         }
 
@@ -9665,5 +9738,15 @@
             this.text = b.processLegacyText(text, ambient);
             return this;
         }
+
+        /**
+         * Set the maximum lines of remote input history lines allowed.
+         * @param maxRemoteInputHistory The number of lines.
+         * @return The builder for method chaining.
+         */
+        public StandardTemplateParams setMaxRemoteInputHistory(int maxRemoteInputHistory) {
+            this.maxRemoteInputHistory = maxRemoteInputHistory;
+            return this;
+        }
     }
 }
diff --git a/core/java/android/app/StatsManager.java b/core/java/android/app/StatsManager.java
index 45754ae..32fc0dc 100644
--- a/core/java/android/app/StatsManager.java
+++ b/core/java/android/app/StatsManager.java
@@ -115,8 +115,9 @@
         }
     }
 
+    // TODO: Temporary for backwards compatibility. Remove.
     /**
-     * TODO: Temporary for backwards compatibility. Remove.
+     * @deprecated Use {@link #addConfig(long, byte[])}
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public boolean addConfiguration(long configKey, byte[] config) {
@@ -149,8 +150,9 @@
         }
     }
 
+    // TODO: Temporary for backwards compatibility. Remove.
     /**
-     * TODO: Temporary for backwards compatibility. Remove.
+     * @deprecated Use {@link #removeConfig(long)}
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public boolean removeConfiguration(long configKey) {
@@ -216,8 +218,9 @@
         }
     }
 
+    // TODO: Temporary for backwards compatibility. Remove.
     /**
-     * TODO: Temporary for backwards compatibility. Remove.
+     * @deprecated Use {@link #setBroadcastSubscriber(PendingIntent, long, long)}
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public boolean setBroadcastSubscriber(
@@ -268,8 +271,9 @@
         }
     }
 
+    // TODO: Temporary for backwards compatibility. Remove.
     /**
-     * TODO: Temporary for backwards compatibility. Remove.
+     * @deprecated Use {@link #setFetchReportsOperation(PendingIntent, long)}
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public boolean setDataFetchOperation(long configKey, PendingIntent pendingIntent) {
@@ -304,8 +308,9 @@
         }
     }
 
+    // TODO: Temporary for backwards compatibility. Remove.
     /**
-     * TODO: Temporary for backwards compatibility. Remove.
+     * @deprecated Use {@link #getReports(long)}
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public @Nullable byte[] getData(long configKey) {
@@ -339,12 +344,9 @@
         }
     }
 
+    // TODO: Temporary for backwards compatibility. Remove.
     /**
-     * Clients can request metadata for statsd. Will contain stats across all configurations but not
-     * the actual metrics themselves (metrics must be collected via {@link #getReports(long)}.
-     * This getter is not destructive and will not reset any metrics/counters.
-     *
-     * @return Serialized StatsdStatsReport proto. Returns null on failure (eg, if statsd crashed).
+     * @deprecated Use {@link #getStatsMetadata()}
      */
     @RequiresPermission(allOf = { DUMP, PACKAGE_USAGE_STATS })
     public @Nullable byte[] getMetadata() {
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/backup/BackupManager.java b/core/java/android/app/backup/BackupManager.java
index 30f340c..e7ae32d 100644
--- a/core/java/android/app/backup/BackupManager.java
+++ b/core/java/android/app/backup/BackupManager.java
@@ -443,6 +443,27 @@
     }
 
     /**
+     * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+     * null} if no transport selected or if the transport selected is not registered.
+     *
+     * @hide
+     */
+    @SystemApi
+    @RequiresPermission(android.Manifest.permission.BACKUP)
+    @Nullable
+    public ComponentName getCurrentTransportComponent() {
+        checkServiceBinder();
+        if (sService != null) {
+            try {
+                return sService.getCurrentTransportComponent();
+            } catch (RemoteException e) {
+                Log.e(TAG, "getCurrentTransportComponent() couldn't connect");
+            }
+        }
+        return null;
+    }
+
+    /**
      * Request a list of all available backup transports' names.
      *
      * @hide
diff --git a/core/java/android/app/backup/IBackupManager.aidl b/core/java/android/app/backup/IBackupManager.aidl
index f3ca746..1c55d8a 100644
--- a/core/java/android/app/backup/IBackupManager.aidl
+++ b/core/java/android/app/backup/IBackupManager.aidl
@@ -244,8 +244,6 @@
      *     {@code null} and MUST NOT be {@code null} when dataManagementIntent is not {@code null}.
      * @throws SecurityException If the UID of the calling process differs from the package UID of
      *     {@code transportComponent} or if the caller does NOT have BACKUP permission.
-     *
-     * @hide
      */
     void updateTransportAttributes(in ComponentName transportComponent, in String name,
             in Intent configurationIntent, in String currentDestinationString,
@@ -257,6 +255,13 @@
      */
     String getCurrentTransport();
 
+     /**
+      * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+      * null} if no transport selected or if the transport selected is not registered.  Callers must
+      * hold the android.permission.BACKUP permission to use this method.
+      */
+    ComponentName getCurrentTransportComponent();
+
     /**
      * Request a list of all available backup transports' names.  Callers must
      * hold the android.permission.BACKUP permission to use this method.
@@ -296,8 +301,6 @@
      *                  the transport's name that is returned by {@link BackupTransport#name()}.
      * @param listener A listener object to get a callback on the transport being selected. It may
      *                 be {@code null}.
-     *
-     * @hide
      */
     void selectBackupTransportAsync(in ComponentName transport, ISelectBackupTransportCallback listener);
 
@@ -364,7 +367,6 @@
      * @param result In the case of a full backup measure operation, the estimated
      *        total file size that would result from the operation. Unused in all other
      *        cases.
-     * {@hide}
      */
     void opComplete(int token, long result);
 
diff --git a/core/java/android/app/slice/SliceProvider.java b/core/java/android/app/slice/SliceProvider.java
index 5e75841..4c22c94 100644
--- a/core/java/android/app/slice/SliceProvider.java
+++ b/core/java/android/app/slice/SliceProvider.java
@@ -15,6 +15,8 @@
  */
 package android.app.slice;
 
+import static android.app.slice.Slice.SUBTYPE_COLOR;
+
 import android.annotation.NonNull;
 import android.app.PendingIntent;
 import android.content.ComponentName;
@@ -29,6 +31,7 @@
 import android.content.pm.ProviderInfo;
 import android.database.ContentObserver;
 import android.database.Cursor;
+import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
 import android.os.Bundle;
@@ -39,6 +42,8 @@
 import android.os.StrictMode.ThreadPolicy;
 import android.util.ArraySet;
 import android.util.Log;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -472,12 +477,25 @@
         }
         Slice.Builder parent = new Slice.Builder(sliceUri);
         Slice.Builder childAction = new Slice.Builder(parent)
+                .addIcon(Icon.createWithResource(context,
+                        com.android.internal.R.drawable.ic_permission), null,
+                        Collections.emptyList())
                 .addHints(Arrays.asList(Slice.HINT_TITLE, Slice.HINT_SHORTCUT))
                 .addAction(action, new Slice.Builder(parent).build(), null);
 
+        TypedValue tv = new TypedValue();
+        new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_Light)
+                .getTheme().resolveAttribute(android.R.attr.colorAccent, tv, true);
+        int deviceDefaultAccent = tv.data;
+
         parent.addSubSlice(new Slice.Builder(sliceUri.buildUpon().appendPath("permission").build())
+                .addIcon(Icon.createWithResource(context,
+                        com.android.internal.R.drawable.ic_arrow_forward), null,
+                        Collections.emptyList())
                 .addText(getPermissionString(context, callingPackage), null,
                         Collections.emptyList())
+                .addInt(deviceDefaultAccent, SUBTYPE_COLOR,
+                        Collections.emptyList())
                 .addSubSlice(childAction.build(), null)
                 .build(), null);
         return parent.addHints(Arrays.asList(Slice.HINT_PERMISSION_REQUEST)).build();
diff --git a/core/java/android/app/usage/UsageEvents.java b/core/java/android/app/usage/UsageEvents.java
index 503ca6c..3e90af3 100644
--- a/core/java/android/app/usage/UsageEvents.java
+++ b/core/java/android/app/usage/UsageEvents.java
@@ -399,16 +399,20 @@
      * {@hide}
      */
     public UsageEvents(Parcel in) {
-        mEventCount = in.readInt();
-        mIndex = in.readInt();
+        byte[] bytes = in.readBlob();
+        Parcel data = Parcel.obtain();
+        data.unmarshall(bytes, 0, bytes.length);
+        data.setDataPosition(0);
+        mEventCount = data.readInt();
+        mIndex = data.readInt();
         if (mEventCount > 0) {
-            mStringPool = in.createStringArray();
+            mStringPool = data.createStringArray();
 
-            final int listByteLength = in.readInt();
-            final int positionInParcel = in.readInt();
+            final int listByteLength = data.readInt();
+            final int positionInParcel = data.readInt();
             mParcel = Parcel.obtain();
             mParcel.setDataPosition(0);
-            mParcel.appendFrom(in, in.dataPosition(), listByteLength);
+            mParcel.appendFrom(data, data.dataPosition(), listByteLength);
             mParcel.setDataSize(mParcel.dataPosition());
             mParcel.setDataPosition(positionInParcel);
         }
@@ -586,10 +590,11 @@
 
     @Override
     public void writeToParcel(Parcel dest, int flags) {
-        dest.writeInt(mEventCount);
-        dest.writeInt(mIndex);
+        Parcel data = Parcel.obtain();
+        data.writeInt(mEventCount);
+        data.writeInt(mIndex);
         if (mEventCount > 0) {
-            dest.writeStringArray(mStringPool);
+            data.writeStringArray(mStringPool);
 
             if (mEventsToWrite != null) {
                 // Write out the events
@@ -604,31 +609,34 @@
                     final int listByteLength = p.dataPosition();
 
                     // Write the total length of the data.
-                    dest.writeInt(listByteLength);
+                    data.writeInt(listByteLength);
 
                     // Write our current position into the data.
-                    dest.writeInt(0);
+                    data.writeInt(0);
 
                     // Write the data.
-                    dest.appendFrom(p, 0, listByteLength);
+                    data.appendFrom(p, 0, listByteLength);
                 } finally {
                     p.recycle();
                 }
 
             } else if (mParcel != null) {
                 // Write the total length of the data.
-                dest.writeInt(mParcel.dataSize());
+                data.writeInt(mParcel.dataSize());
 
                 // Write out current position into the data.
-                dest.writeInt(mParcel.dataPosition());
+                data.writeInt(mParcel.dataPosition());
 
                 // Write the data.
-                dest.appendFrom(mParcel, 0, mParcel.dataSize());
+                data.appendFrom(mParcel, 0, mParcel.dataSize());
             } else {
                 throw new IllegalStateException(
                         "Either mParcel or mEventsToWrite must not be null");
             }
         }
+        // Data can be too large for a transact. Write the data as a Blob, which will be written to
+        // ashmem if too large.
+        dest.writeBlob(data.marshall());
     }
 
     public static final Creator<UsageEvents> CREATOR = new Creator<UsageEvents>() {
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/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index 1461711..0e91a29 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -1188,6 +1188,7 @@
      * Determines whether the {@link Activity} is considered translucent or floating.
      * @hide
      */
+    @TestApi
     public static boolean isTranslucentOrFloating(TypedArray attributes) {
         final boolean isTranslucent =
                 attributes.getBoolean(com.android.internal.R.styleable.Window_windowIsTranslucent,
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 69bc353..aa0cacb 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
@@ -1656,7 +1664,8 @@
     /**
      * Feature for {@link #getSystemAvailableFeatures} and
      * {@link #hasSystemFeature}: The device includes at least one form of audio
-     * output, such as speakers, audio jack or streaming over bluetooth
+     * output, as defined in the Android Compatibility Definition Document (CDD)
+     * <a href="https://source.android.com/compatibility/android-cdd#7_8_audio">section 7.8 Audio</a>.
      */
     @SdkConstant(SdkConstantType.FEATURE)
     public static final String FEATURE_AUDIO_OUTPUT = "android.hardware.audio.output";
@@ -4845,7 +4854,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/CameraMetadata.java b/core/java/android/hardware/camera2/CameraMetadata.java
index 262de15..1275a85 100644
--- a/core/java/android/hardware/camera2/CameraMetadata.java
+++ b/core/java/android/hardware/camera2/CameraMetadata.java
@@ -813,6 +813,10 @@
     /**
      * <p>The camera device is a logical camera backed by two or more physical cameras that are
      * also exposed to the application.</p>
+     * <p>Camera application shouldn't assume that there are at most 1 rear camera and 1 front
+     * camera in the system. For an application that switches between front and back cameras,
+     * the recommendation is to switch between the first rear camera and the first front
+     * camera in the list of supported camera devices.</p>
      * <p>This capability requires the camera device to support the following:</p>
      * <ul>
      * <li>This camera device must list the following static metadata entries in {@link android.hardware.camera2.CameraCharacteristics }:<ul>
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/inputmethodservice/KeyboardView.java b/core/java/android/inputmethodservice/KeyboardView.java
index 2306e5f..16c1f6d 100644
--- a/core/java/android/inputmethodservice/KeyboardView.java
+++ b/core/java/android/inputmethodservice/KeyboardView.java
@@ -21,18 +21,15 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Paint;
+import android.graphics.Paint.Align;
 import android.graphics.PorterDuff;
 import android.graphics.Rect;
 import android.graphics.Typeface;
-import android.graphics.Paint.Align;
-import android.graphics.Region.Op;
 import android.graphics.drawable.Drawable;
 import android.inputmethodservice.Keyboard.Key;
 import android.media.AudioManager;
 import android.os.Handler;
 import android.os.Message;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.AttributeSet;
 import android.util.TypedValue;
 import android.view.GestureDetector;
@@ -662,11 +659,13 @@
             invalidateAllKeys();
             mKeyboardChanged = false;
         }
-        final Canvas canvas = mCanvas;
-        canvas.clipRect(mDirtyRect, Op.REPLACE);
 
         if (mKeyboard == null) return;
 
+        mCanvas.save();
+        final Canvas canvas = mCanvas;
+        canvas.clipRect(mDirtyRect);
+
         final Paint paint = mPaint;
         final Drawable keyBackground = mKeyBackground;
         final Rect clipRegion = mClipRegion;
@@ -758,7 +757,7 @@
             paint.setColor(0xFF00FF00);
             canvas.drawCircle((mStartX + mLastX) / 2, (mStartY + mLastY) / 2, 2, paint);
         }
-
+        mCanvas.restore();
         mDrawPending = false;
         mDirtyRect.setEmpty();
     }
diff --git a/core/java/android/net/ConnectivityManager.java b/core/java/android/net/ConnectivityManager.java
index c3b8f39..c5cb1f5 100644
--- a/core/java/android/net/ConnectivityManager.java
+++ b/core/java/android/net/ConnectivityManager.java
@@ -238,6 +238,14 @@
     public static final String EXTRA_CAPTIVE_PORTAL_URL = "android.net.extra.CAPTIVE_PORTAL_URL";
 
     /**
+     * Key for passing a {@link android.net.captiveportal.CaptivePortalProbeSpec} to the captive
+     * portal login activity.
+     * {@hide}
+     */
+    public static final String EXTRA_CAPTIVE_PORTAL_PROBE_SPEC =
+            "android.net.extra.CAPTIVE_PORTAL_PROBE_SPEC";
+
+    /**
      * Key for passing a user agent string to the captive portal login activity.
      * {@hide}
      */
diff --git a/core/java/android/net/Network.java b/core/java/android/net/Network.java
index 15a0ee5..d75d439 100644
--- a/core/java/android/net/Network.java
+++ b/core/java/android/net/Network.java
@@ -85,6 +85,21 @@
     private static final long HANDLE_MAGIC = 0xcafed00dL;
     private static final int HANDLE_MAGIC_SIZE = 32;
 
+    // A boolean to control how getAllByName()/getByName() behaves in the face
+    // of Private DNS.
+    //
+    // When true, these calls will request that DNS resolution bypass any
+    // Private DNS that might otherwise apply. Use of this feature is restricted
+    // and permission checks are made by netd (attempts to bypass Private DNS
+    // without appropriate permission are silently turned into vanilla DNS
+    // requests). This only affects DNS queries made using this network object.
+    //
+    // It it not parceled to receivers because (a) it can be set or cleared at
+    // anytime and (b) receivers should be explicit about attempts to bypass
+    // Private DNS so that the intent of the code is easily determined and
+    // code search audits are possible.
+    private boolean mPrivateDnsBypass = false;
+
     /**
      * @hide
      */
@@ -108,7 +123,7 @@
      * @throws UnknownHostException if the address lookup fails.
      */
     public InetAddress[] getAllByName(String host) throws UnknownHostException {
-        return InetAddress.getAllByNameOnNet(host, netId);
+        return InetAddress.getAllByNameOnNet(host, getNetIdForResolv());
     }
 
     /**
@@ -122,7 +137,32 @@
      *             if the address lookup fails.
      */
     public InetAddress getByName(String host) throws UnknownHostException {
-        return InetAddress.getByNameOnNet(host, netId);
+        return InetAddress.getByNameOnNet(host, getNetIdForResolv());
+    }
+
+    /**
+     * Specify whether or not Private DNS should be bypassed when attempting
+     * to use {@link getAllByName()}/{@link getByName()} methods on the given
+     * instance for hostname resolution.
+     *
+     * @hide
+     */
+    public void setPrivateDnsBypass(boolean bypass) {
+        mPrivateDnsBypass = bypass;
+    }
+
+    /**
+     * Returns a netid marked with the Private DNS bypass flag.
+     *
+     * This flag must be kept in sync with the NETID_USE_LOCAL_NAMESERVERS flag
+     * in system/netd/include/NetdClient.h.
+     *
+     * @hide
+     */
+    public int getNetIdForResolv() {
+        return mPrivateDnsBypass
+                ? (int) (0x80000000L | (long) netId)  // Non-portable DNS resolution flag.
+                : netId;
     }
 
     /**
diff --git a/core/java/android/net/NetworkStats.java b/core/java/android/net/NetworkStats.java
index f0dd262..edf9bc1 100644
--- a/core/java/android/net/NetworkStats.java
+++ b/core/java/android/net/NetworkStats.java
@@ -1100,6 +1100,8 @@
     public interface NonMonotonicObserver<C> {
         public void foundNonMonotonic(
                 NetworkStats left, int leftIndex, NetworkStats right, int rightIndex, C cookie);
+        public void foundNonMonotonic(
+                NetworkStats stats, int statsIndex, C cookie);
     }
 
     /**
diff --git a/core/java/android/net/SntpClient.java b/core/java/android/net/SntpClient.java
index 66cdc99..ddf63ca 100644
--- a/core/java/android/net/SntpClient.java
+++ b/core/java/android/net/SntpClient.java
@@ -84,6 +84,10 @@
      * @return true if the transaction was successful.
      */
     public boolean requestTime(String host, int timeout, Network network) {
+        // This flag only affects DNS resolution and not other socket semantics,
+        // therefore it's safe to set unilaterally rather than take more
+        // defensive measures like making a copy.
+        network.setPrivateDnsBypass(true);
         InetAddress address = null;
         try {
             address = network.getByName(host);
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
index 614c0b8..1634694 100644
--- a/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeResult.java
@@ -16,6 +16,8 @@
 
 package android.net.captiveportal;
 
+import android.annotation.Nullable;
+
 /**
  * Result of calling isCaptivePortal().
  * @hide
@@ -23,6 +25,7 @@
 public final class CaptivePortalProbeResult {
     public static final int SUCCESS_CODE = 204;
     public static final int FAILED_CODE = 599;
+    public static final int PORTAL_CODE = 302;
 
     public static final CaptivePortalProbeResult FAILED = new CaptivePortalProbeResult(FAILED_CODE);
     public static final CaptivePortalProbeResult SUCCESS =
@@ -32,15 +35,23 @@
     public final String redirectUrl;      // Redirect destination returned from Internet probe.
     public final String detectUrl;        // URL where a 204 response code indicates
                                           // captive portal has been appeased.
+    @Nullable
+    public final CaptivePortalProbeSpec probeSpec;
 
     public CaptivePortalProbeResult(int httpResponseCode) {
         this(httpResponseCode, null, null);
     }
 
     public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl) {
+        this(httpResponseCode, redirectUrl, detectUrl, null);
+    }
+
+    public CaptivePortalProbeResult(int httpResponseCode, String redirectUrl, String detectUrl,
+            CaptivePortalProbeSpec probeSpec) {
         mHttpResponseCode = httpResponseCode;
         this.redirectUrl = redirectUrl;
         this.detectUrl = detectUrl;
+        this.probeSpec = probeSpec;
     }
 
     public boolean isSuccessful() {
diff --git a/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
new file mode 100644
index 0000000..57a926a
--- /dev/null
+++ b/core/java/android/net/captiveportal/CaptivePortalProbeSpec.java
@@ -0,0 +1,180 @@
+/*
+ * 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.
+ */
+
+package android.net.captiveportal;
+
+import static android.net.captiveportal.CaptivePortalProbeResult.PORTAL_CODE;
+import static android.net.captiveportal.CaptivePortalProbeResult.SUCCESS_CODE;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.text.TextUtils;
+import android.util.Log;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.ParseException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Pattern;
+import java.util.regex.PatternSyntaxException;
+
+/** @hide */
+public abstract class CaptivePortalProbeSpec {
+    public static final String HTTP_LOCATION_HEADER_NAME = "Location";
+
+    private static final String TAG = CaptivePortalProbeSpec.class.getSimpleName();
+    private static final String REGEX_SEPARATOR = "@@/@@";
+    private static final String SPEC_SEPARATOR = "@@,@@";
+
+    private final String mEncodedSpec;
+    private final URL mUrl;
+
+    CaptivePortalProbeSpec(String encodedSpec, URL url) {
+        mEncodedSpec = encodedSpec;
+        mUrl = url;
+    }
+
+    /**
+     * Parse a {@link CaptivePortalProbeSpec} from a {@link String}.
+     *
+     * <p>The valid format is a URL followed by two regular expressions, each separated by "@@/@@".
+     * @throws MalformedURLException The URL has invalid format for {@link URL#URL(String)}.
+     * @throws ParseException The string is empty, does not match the above format, or a regular
+     * expression is invalid for {@link Pattern#compile(String)}.
+     */
+    @NonNull
+    public static CaptivePortalProbeSpec parseSpec(String spec) throws ParseException,
+            MalformedURLException {
+        if (TextUtils.isEmpty(spec)) {
+            throw new ParseException("Empty probe spec", 0 /* errorOffset */);
+        }
+
+        String[] splits = TextUtils.split(spec, REGEX_SEPARATOR);
+        if (splits.length != 3) {
+            throw new ParseException("Probe spec does not have 3 parts", 0 /* errorOffset */);
+        }
+
+        final int statusRegexPos = splits[0].length() + REGEX_SEPARATOR.length();
+        final int locationRegexPos = statusRegexPos + splits[1].length() + REGEX_SEPARATOR.length();
+        final Pattern statusRegex = parsePatternIfNonEmpty(splits[1], statusRegexPos);
+        final Pattern locationRegex = parsePatternIfNonEmpty(splits[2], locationRegexPos);
+
+        return new RegexMatchProbeSpec(spec, new URL(splits[0]), statusRegex, locationRegex);
+    }
+
+    @Nullable
+    private static Pattern parsePatternIfNonEmpty(String pattern, int pos) throws ParseException {
+        if (TextUtils.isEmpty(pattern)) {
+            return null;
+        }
+        try {
+            return Pattern.compile(pattern);
+        } catch (PatternSyntaxException e) {
+            throw new ParseException(
+                    String.format("Invalid status pattern [%s]: %s", pattern, e),
+                    pos /* errorOffset */);
+        }
+    }
+
+    /**
+     * Parse a {@link CaptivePortalProbeSpec} from a {@link String}, or return a fallback spec
+     * based on the status code of the provided URL if the spec cannot be parsed.
+     */
+    @Nullable
+    public static CaptivePortalProbeSpec parseSpecOrNull(@Nullable String spec) {
+        if (spec != null) {
+            try {
+                return parseSpec(spec);
+            } catch (ParseException | MalformedURLException e) {
+                Log.e(TAG, "Invalid probe spec: " + spec, e);
+                // Fall through
+            }
+        }
+        return null;
+    }
+
+    /**
+     * Parse a config String to build an array of {@link CaptivePortalProbeSpec}.
+     *
+     * <p>Each spec is separated by @@,@@ and follows the format for {@link #parseSpec(String)}.
+     * <p>This method does not throw but ignores any entry that could not be parsed.
+     */
+    public static CaptivePortalProbeSpec[] parseCaptivePortalProbeSpecs(String settingsVal) {
+        List<CaptivePortalProbeSpec> specs = new ArrayList<>();
+        if (settingsVal != null) {
+            for (String spec : TextUtils.split(settingsVal, SPEC_SEPARATOR)) {
+                try {
+                    specs.add(parseSpec(spec));
+                } catch (ParseException | MalformedURLException e) {
+                    Log.e(TAG, "Invalid probe spec: " + spec, e);
+                }
+            }
+        }
+
+        if (specs.isEmpty()) {
+            Log.e(TAG, String.format("could not create any validation spec from %s", settingsVal));
+        }
+        return specs.toArray(new CaptivePortalProbeSpec[specs.size()]);
+    }
+
+    /**
+     * Get the probe result from HTTP status and location header.
+     */
+    public abstract CaptivePortalProbeResult getResult(int status, @Nullable String locationHeader);
+
+    public String getEncodedSpec() {
+        return mEncodedSpec;
+    }
+
+    public URL getUrl() {
+        return mUrl;
+    }
+
+    /**
+     * Implementation of {@link CaptivePortalProbeSpec} that is based on configurable regular
+     * expressions for the HTTP status code and location header (if any). Matches indicate that
+     * the page is not a portal.
+     * This probe cannot fail: it always returns SUCCESS_CODE or PORTAL_CODE
+     */
+    private static class RegexMatchProbeSpec extends CaptivePortalProbeSpec {
+        @Nullable
+        final Pattern mStatusRegex;
+        @Nullable
+        final Pattern mLocationHeaderRegex;
+
+        RegexMatchProbeSpec(
+                String spec, URL url, Pattern statusRegex, Pattern locationHeaderRegex) {
+            super(spec, url);
+            mStatusRegex = statusRegex;
+            mLocationHeaderRegex = locationHeaderRegex;
+        }
+
+        @Override
+        public CaptivePortalProbeResult getResult(int status, String locationHeader) {
+            final boolean statusMatch = safeMatch(String.valueOf(status), mStatusRegex);
+            final boolean locationMatch = safeMatch(locationHeader, mLocationHeaderRegex);
+            final int returnCode = statusMatch && locationMatch ? SUCCESS_CODE : PORTAL_CODE;
+            return new CaptivePortalProbeResult(
+                    returnCode, locationHeader, getUrl().toString(), this);
+        }
+    }
+
+    private static boolean safeMatch(@Nullable String value, @Nullable Pattern pattern) {
+        // No value is a match ("no location header" passes the location rule for non-redirects)
+        return pattern == null || TextUtils.isEmpty(value) || pattern.matcher(value).matches();
+    }
+}
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index 619ec23..221abed 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -245,8 +245,10 @@
      * New in version 31:
      *   - New cellular network types.
      *   - Deferred job metrics.
+     * New in version 32:
+     *   - Ambient display properly output in data dump.
      */
-    static final int CHECKIN_VERSION = 31;
+    static final int CHECKIN_VERSION = 32;
 
     /**
      * Old version, we hit 9 and ran out of room, need to remove.
diff --git a/core/java/android/os/Binder.java b/core/java/android/os/Binder.java
index 5890d98..7e7d617 100644
--- a/core/java/android/os/Binder.java
+++ b/core/java/android/os/Binder.java
@@ -138,6 +138,15 @@
     }
 
     /**
+     * Dump proxy debug information.
+     *
+     * @hide
+     */
+    public static void dumpProxyDebugInfo() {
+        BinderProxy.dumpProxyDebugInfo();
+    }
+
+    /**
      * Check if binder transaction tracing is enabled.
      *
      * @hide
@@ -942,8 +951,7 @@
                     // about to crash.
                     final int totalUnclearedSize = unclearedSize();
                     if (totalUnclearedSize >= CRASH_AT_SIZE) {
-                        dumpProxyInterfaceCounts();
-                        dumpPerUidProxyCounts();
+                        dumpProxyDebugInfo();
                         Runtime.getRuntime().gc();
                         throw new AssertionError("Binder ProxyMap has too many entries: "
                                 + totalSize + " (total), " + totalUnclearedSize + " (uncleared), "
@@ -1028,6 +1036,14 @@
     private static ProxyMap sProxyMap = new ProxyMap();
 
     /**
+      * @hide
+      */
+    public static void dumpProxyDebugInfo() {
+        sProxyMap.dumpProxyInterfaceCounts();
+        sProxyMap.dumpPerUidProxyCounts();
+    }
+
+    /**
      * Return a BinderProxy for IBinder.
      * This method is thread-hostile!  The (native) caller serializes getInstance() calls using
      * gProxyLock.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index 5e23932..3017f25 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -45,6 +45,7 @@
             in String[] disallowedPackages);
     UserInfo createRestrictedProfile(String name, int parentUserHandle);
     void setUserEnabled(int userHandle);
+    void setUserAdmin(int userId);
     void evictCredentialEncryptionKey(int userHandle);
     boolean removeUser(int userHandle);
     boolean removeUserEvenWhenDisallowed(int userHandle);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 48e019d..bc3d870 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -2091,12 +2091,33 @@
      * Also ephemeral users can be disabled to indicate that their removal is in progress and they
      * shouldn't be re-entered. Therefore ephemeral users should not be re-enabled once disabled.
      *
-     * @param userHandle the id of the profile to enable
+     * @param userId the id of the profile to enable
      * @hide
      */
-    public void setUserEnabled(@UserIdInt int userHandle) {
+    public void setUserEnabled(@UserIdInt int userId) {
         try {
-            mService.setUserEnabled(userHandle);
+            mService.setUserEnabled(userId);
+        } catch (RemoteException re) {
+            throw re.rethrowFromSystemServer();
+        }
+    }
+
+    /**
+     * Assigns admin privileges to the user, if such a user exists.
+     *
+     * <p>Requires {@link android.Manifest.permission#MANAGE_USERS} and
+     * {@link android.Manifest.permission#INTERACT_ACROSS_USERS_FULL} permissions.
+     *
+     * @param userHandle the id of the user to become admin
+     * @hide
+     */
+    @RequiresPermission(allOf = {
+            Manifest.permission.INTERACT_ACROSS_USERS_FULL,
+            Manifest.permission.MANAGE_USERS
+    })
+    public void setUserAdmin(@UserIdInt int userHandle) {
+        try {
+            mService.setUserAdmin(userHandle);
         } catch (RemoteException re) {
             throw re.rethrowFromSystemServer();
         }
diff --git a/core/java/android/os/VibrationEffect.java b/core/java/android/os/VibrationEffect.java
index 62359ec..91c69fb 100644
--- a/core/java/android/os/VibrationEffect.java
+++ b/core/java/android/os/VibrationEffect.java
@@ -18,6 +18,7 @@
 
 import android.annotation.Nullable;
 import android.annotation.TestApi;
+import android.content.ContentResolver;
 import android.content.Context;
 import android.hardware.vibrator.V1_0.EffectStrength;
 import android.hardware.vibrator.V1_2.Effect;
@@ -277,7 +278,12 @@
             if (uris[i] == null) {
                 continue;
             }
-            if (Uri.parse(uris[i]).equals(uri)) {
+            ContentResolver cr = context.getContentResolver();
+            Uri mappedUri = cr.uncanonicalize(Uri.parse(uris[i]));
+            if (mappedUri == null) {
+                continue;
+            }
+            if (mappedUri.equals(uri)) {
                 return get(RINGTONES[i]);
             }
         }
diff --git a/core/java/android/os/Vibrator.java b/core/java/android/os/Vibrator.java
index f1f6f41..d2d8f1e 100644
--- a/core/java/android/os/Vibrator.java
+++ b/core/java/android/os/Vibrator.java
@@ -72,12 +72,23 @@
     public @interface VibrationIntensity{}
 
     private final String mPackageName;
+    // The default vibration intensity level for haptic feedback.
+    @VibrationIntensity
+    private final int mDefaultHapticFeedbackIntensity;
+    // The default vibration intensity level for notifications.
+    @VibrationIntensity
+    private final int mDefaultNotificationVibrationIntensity;
 
     /**
      * @hide to prevent subclassing from outside of the framework
      */
     public Vibrator() {
         mPackageName = ActivityThread.currentPackageName();
+        final Context ctx = ActivityThread.currentActivityThread().getSystemContext();
+        mDefaultHapticFeedbackIntensity = loadDefaultIntensity(ctx,
+                com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
+        mDefaultNotificationVibrationIntensity = loadDefaultIntensity(ctx,
+                com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
     }
 
     /**
@@ -85,6 +96,14 @@
      */
     protected Vibrator(Context context) {
         mPackageName = context.getOpPackageName();
+        mDefaultHapticFeedbackIntensity = loadDefaultIntensity(context,
+                com.android.internal.R.integer.config_defaultHapticFeedbackIntensity);
+        mDefaultNotificationVibrationIntensity = loadDefaultIntensity(context,
+                com.android.internal.R.integer.config_defaultNotificationVibrationIntensity);
+    }
+
+    private int loadDefaultIntensity(Context ctx, int resId) {
+        return ctx != null ? ctx.getResources().getInteger(resId) : VIBRATION_INTENSITY_MEDIUM;
     }
 
     /**
@@ -92,7 +111,7 @@
      * @hide
      */
     public int getDefaultHapticFeedbackIntensity() {
-        return VIBRATION_INTENSITY_MEDIUM;
+        return mDefaultHapticFeedbackIntensity;
     }
 
     /**
@@ -100,7 +119,7 @@
      * @hide
      */
     public int getDefaultNotificationVibrationIntensity() {
-        return VIBRATION_INTENSITY_HIGH;
+        return mDefaultNotificationVibrationIntensity;
     }
 
     /**
diff --git a/core/java/android/os/ZygoteProcess.java b/core/java/android/os/ZygoteProcess.java
index 6994033..021e72f 100644
--- a/core/java/android/os/ZygoteProcess.java
+++ b/core/java/android/os/ZygoteProcess.java
@@ -467,6 +467,35 @@
     }
 
     /**
+     * Attempt to retrieve the PID of the zygote serving the given abi.
+     */
+    public int getZygotePid(String abi) {
+        try {
+            synchronized (mLock) {
+                ZygoteState state = openZygoteSocketIfNeeded(abi);
+
+                // Each query starts with the argument count (1 in this case)
+                state.writer.write("1");
+                // ... followed by a new-line.
+                state.writer.newLine();
+                // ... followed by our only argument.
+                state.writer.write("--get-pid");
+                state.writer.newLine();
+                state.writer.flush();
+
+                // The response is a length prefixed stream of ASCII bytes.
+                int numBytes = state.inputStream.readInt();
+                byte[] bytes = new byte[numBytes];
+                state.inputStream.readFully(bytes);
+
+                return Integer.parseInt(new String(bytes, StandardCharsets.US_ASCII));
+            }
+        } catch (Exception ex) {
+            throw new RuntimeException("Failure retrieving pid", ex);
+        }
+    }
+
+    /**
      * Push hidden API blacklisting exemptions into the zygote process(es).
      *
      * <p>The list of exemptions will take affect for all new processes forked from the zygote after
diff --git a/core/java/android/os/storage/VolumeInfo.java b/core/java/android/os/storage/VolumeInfo.java
index 576ea52..8d4c3c3 100644
--- a/core/java/android/os/storage/VolumeInfo.java
+++ b/core/java/android/os/storage/VolumeInfo.java
@@ -407,8 +407,12 @@
      * {@link #TYPE_EMULATED} or {@link #TYPE_PUBLIC}.
      */
     public @Nullable Intent buildBrowseIntent() {
+        return buildBrowseIntentForUser(UserHandle.myUserId());
+    }
+
+    public @Nullable Intent buildBrowseIntentForUser(int userId) {
         final Uri uri;
-        if (type == VolumeInfo.TYPE_PUBLIC && mountUserId == UserHandle.myUserId()) {
+        if (type == VolumeInfo.TYPE_PUBLIC && mountUserId == userId) {
             uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY, fsUuid);
         } else if (type == VolumeInfo.TYPE_EMULATED && isPrimary()) {
             uri = DocumentsContract.buildRootUri(DOCUMENT_AUTHORITY,
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 931ac92..67778d3 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -23,6 +23,7 @@
 import static android.provider.SettingsValidators.LENIENT_IP_ADDRESS_VALIDATOR;
 import static android.provider.SettingsValidators.LOCALE_VALIDATOR;
 import static android.provider.SettingsValidators.NON_NEGATIVE_INTEGER_VALIDATOR;
+import static android.provider.SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR;
 import static android.provider.SettingsValidators.PACKAGE_NAME_VALIDATOR;
 import static android.provider.SettingsValidators.URI_VALIDATOR;
 
@@ -5461,7 +5462,8 @@
         @TestApi
         public static final String AUTOFILL_SERVICE = "autofill_service";
 
-        private static final Validator AUTOFILL_SERVICE_VALIDATOR = COMPONENT_NAME_VALIDATOR;
+        private static final Validator AUTOFILL_SERVICE_VALIDATOR =
+                NULLABLE_COMPONENT_NAME_VALIDATOR;
 
         /**
          * Boolean indicating if Autofill supports field classification.
@@ -5959,7 +5961,7 @@
                 "accessibility_shortcut_target_service";
 
         private static final Validator ACCESSIBILITY_SHORTCUT_TARGET_SERVICE_VALIDATOR =
-                COMPONENT_NAME_VALIDATOR;
+                NULLABLE_COMPONENT_NAME_VALIDATOR;
 
         /**
          * Setting specifying the accessibility service or feature to be toggled via the
@@ -7119,6 +7121,35 @@
         public static final String UI_NIGHT_MODE = "ui_night_mode";
 
         /**
+         * The current device UI theme mode effect SystemUI and Launcher.<br/>
+         * <b>Values:</b><br/>
+         * 0 - The mode that theme will controlled by wallpaper color.<br/>
+         * 1 - The mode that will always light theme.<br/>
+         * 2 - The mode that will always dark theme.<br/>
+         *
+         * @hide
+         */
+        public static final String THEME_MODE = "theme_mode";
+
+        /**
+         * THEME_MODE value for wallpaper mode.
+         * @hide
+         */
+        public static final int THEME_MODE_WALLPAPER = 0;
+
+        /**
+         * THEME_MODE value for light theme mode.
+         * @hide
+         */
+        public static final int THEME_MODE_LIGHT = 1;
+
+        /**
+         * THEME_MODE value for dark theme mode.
+         * @hide
+         */
+        public static final int THEME_MODE_DARK = 2;
+
+        /**
          * Whether screensavers are enabled.
          * @hide
          */
@@ -7489,6 +7520,21 @@
         public static final int CAMERA_LIFT_TRIGGER_ENABLED_DEFAULT = 1;
 
         /**
+         * Whether or not the flashlight (camera torch mode) is available required to turn
+         * on flashlight.
+         *
+         * @hide
+         */
+        public static final String FLASHLIGHT_AVAILABLE = "flashlight_available";
+
+        /**
+         * Whether or not flashlight is enabled.
+         *
+         * @hide
+         */
+        public static final String FLASHLIGHT_ENABLED = "flashlight_enabled";
+
+        /**
          * Whether the assist gesture should be enabled.
          *
          * @hide
@@ -10256,6 +10302,15 @@
                 "captive_portal_other_fallback_urls";
 
         /**
+         * A list of captive portal detection specifications used in addition to the fallback URLs.
+         * Each spec has the format url@@/@@statusCodeRegex@@/@@contentRegex. Specs are separated
+         * by "@@,@@".
+         * @hide
+         */
+        public static final String CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS =
+                "captive_portal_fallback_probe_specs";
+
+        /**
          * Whether to use HTTPS for network validation. This is enabled by default and the setting
          * needs to be set to 0 to disable it. This setting is a misnomer because captive portals
          * don't actually use HTTPS, but it's consistent with the other settings.
@@ -11570,6 +11625,13 @@
         /** @hide */ public static final int EMULATE_DISPLAY_CUTOUT_ON = 1;
 
         /**
+         * A colon separated list of keys for Settings Slices.
+         *
+         * @hide
+         */
+        public static final String BLOCKED_SLICES = "blocked_slices";
+
+        /**
          * Defines global zen mode.  ZEN_MODE_OFF, ZEN_MODE_IMPORTANT_INTERRUPTIONS,
          * or ZEN_MODE_NO_INTERRUPTIONS.
          *
diff --git a/core/java/android/provider/SettingsValidators.java b/core/java/android/provider/SettingsValidators.java
index b53b0f0..25e77867 100644
--- a/core/java/android/provider/SettingsValidators.java
+++ b/core/java/android/provider/SettingsValidators.java
@@ -77,6 +77,11 @@
         }
     };
 
+    /**
+     * Does not allow a setting to have a null {@link ComponentName}. Use {@link
+     * SettingsValidators#NULLABLE_COMPONENT_NAME_VALIDATOR} instead if a setting can have a
+     * nullable {@link ComponentName}.
+     */
     public static final Validator COMPONENT_NAME_VALIDATOR = new Validator() {
         @Override
         public boolean validate(@Nullable String value) {
@@ -84,6 +89,16 @@
         }
     };
 
+    /**
+     * Allows a setting to have a null {@link ComponentName}.
+     */
+    public static final Validator NULLABLE_COMPONENT_NAME_VALIDATOR = new Validator() {
+        @Override
+        public boolean validate(@Nullable String value) {
+            return value == null || COMPONENT_NAME_VALIDATOR.validate(value);
+        }
+    };
+
     public static final Validator PACKAGE_NAME_VALIDATOR = new Validator() {
         @Override
         public boolean validate(@Nullable String value) {
diff --git a/core/java/android/service/autofill/FillCallback.java b/core/java/android/service/autofill/FillCallback.java
index 105cd38..0257891 100644
--- a/core/java/android/service/autofill/FillCallback.java
+++ b/core/java/android/service/autofill/FillCallback.java
@@ -70,7 +70,7 @@
         assertNotCalled();
         mCalled = true;
         try {
-            mCallback.onFailure(message);
+            mCallback.onFailure(mRequestId, message);
         } catch (RemoteException e) {
             e.rethrowAsRuntimeException();
         }
diff --git a/core/java/android/service/autofill/IFillCallback.aidl b/core/java/android/service/autofill/IFillCallback.aidl
index 2bb3e9a..1bad1d7 100644
--- a/core/java/android/service/autofill/IFillCallback.aidl
+++ b/core/java/android/service/autofill/IFillCallback.aidl
@@ -28,5 +28,5 @@
 interface IFillCallback {
     void onCancellable(in ICancellationSignal cancellation);
     void onSuccess(in FillResponse response);
-    void onFailure(CharSequence message);
+    void onFailure(int requestId, CharSequence message);
 }
diff --git a/core/java/android/text/Layout.java b/core/java/android/text/Layout.java
index 5ebd28c..92f7a47 100644
--- a/core/java/android/text/Layout.java
+++ b/core/java/android/text/Layout.java
@@ -1004,7 +1004,33 @@
         return TextUtils.packRangeInLong(0, getLineEnd(line));
     }
 
-    /** @hide */
+    /**
+     * Checks if the trailing BiDi level should be used for an offset
+     *
+     * This method is useful when the offset is at the BiDi level transition point and determine
+     * which run need to be used. For example, let's think about following input: (L* denotes
+     * Left-to-Right characters, R* denotes Right-to-Left characters.)
+     * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
+     * Input (Display Order): L1 L2 L3 R3 R2 R1 L4 L5 L6
+     *
+     * Then, think about selecting the range (3, 6). The offset=3 and offset=6 are ambiguous here
+     * since they are at the BiDi transition point.  In Android, the offset is considered to be
+     * associated with the trailing run if the BiDi level of the trailing run is higher than of the
+     * previous run.  In this case, the BiDi level of the input text is as follows:
+     *
+     * Input (Logical Order): L1 L2 L3 R1 R2 R3 L4 L5 L6
+     *              BiDi Run: [ Run 0 ][ Run 1 ][ Run 2 ]
+     *            BiDi Level:  0  0  0  1  1  1  0  0  0
+     *
+     * Thus, offset = 3 is part of Run 1 and this method returns true for offset = 3, since the BiDi
+     * level of Run 1 is higher than the level of Run 0.  Similarly, the offset = 6 is a part of Run
+     * 1 and this method returns false for the offset = 6 since the BiDi level of Run 1 is higher
+     * than the level of Run 2.
+     *
+     * @returns true if offset is at the BiDi level transition point and trailing BiDi level is
+     *          higher than previous BiDi level. See above for the detail.
+     * @hide
+     */
     @VisibleForTesting
     public boolean primaryIsTrailingPrevious(int offset) {
         int line = getLineForOffset(offset);
@@ -1056,6 +1082,43 @@
     }
 
     /**
+     * Computes in linear time the results of calling
+     * #primaryIsTrailingPrevious for all offsets on a line.
+     * @param line The line giving the offsets we compute the information for
+     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean[] primaryIsTrailingPreviousAllLineOffsets(int line) {
+        int lineStart = getLineStart(line);
+        int lineEnd = getLineEnd(line);
+        int[] runs = getLineDirections(line).mDirections;
+
+        boolean[] trailing = new boolean[lineEnd - lineStart + 1];
+
+        byte[] level = new byte[lineEnd - lineStart + 1];
+        for (int i = 0; i < runs.length; i += 2) {
+            int start = lineStart + runs[i];
+            int limit = start + (runs[i + 1] & RUN_LENGTH_MASK);
+            if (limit > lineEnd) {
+                limit = lineEnd;
+            }
+            level[limit - lineStart - 1] =
+                    (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
+        }
+
+        for (int i = 0; i < runs.length; i += 2) {
+            int start = lineStart + runs[i];
+            byte currentLevel = (byte) ((runs[i + 1] >>> RUN_LEVEL_SHIFT) & RUN_LEVEL_MASK);
+            trailing[start - lineStart] = currentLevel > (start == lineStart
+                    ? (getParagraphDirection(line) == 1 ? 0 : 1)
+                    : level[start - lineStart - 1]);
+        }
+
+        return trailing;
+    }
+
+    /**
      * Get the primary horizontal position for the specified text offset.
      * This is the location where a new character would be inserted in
      * the paragraph's primary direction.
@@ -1135,6 +1198,60 @@
     }
 
     /**
+     * Computes in linear time the results of calling
+     * #getHorizontal for all offsets on a line.
+     * @param line The line giving the offsets we compute information for
+     * @param clamped Whether to clamp the results to the width of the layout
+     * @param primary Whether the results should be the primary or the secondary horizontal
+     * @return The array of results, indexed from 0, where 0 corresponds to the line start offset
+     */
+    private float[] getLineHorizontals(int line, boolean clamped, boolean primary) {
+        int start = getLineStart(line);
+        int end = getLineEnd(line);
+        int dir = getParagraphDirection(line);
+        boolean hasTab = getLineContainsTab(line);
+        Directions directions = getLineDirections(line);
+
+        TabStops tabStops = null;
+        if (hasTab && mText instanceof Spanned) {
+            // Just checking this line should be good enough, tabs should be
+            // consistent across all lines in a paragraph.
+            TabStopSpan[] tabs = getParagraphSpans((Spanned) mText, start, end, TabStopSpan.class);
+            if (tabs.length > 0) {
+                tabStops = new TabStops(TAB_INCREMENT, tabs); // XXX should reuse
+            }
+        }
+
+        TextLine tl = TextLine.obtain();
+        tl.set(mPaint, mText, start, end, dir, directions, hasTab, tabStops);
+        boolean[] trailings = primaryIsTrailingPreviousAllLineOffsets(line);
+        if (!primary) {
+            for (int offset = 0; offset < trailings.length; ++offset) {
+                trailings[offset] = !trailings[offset];
+            }
+        }
+        float[] wid = tl.measureAllOffsets(trailings, null);
+        TextLine.recycle(tl);
+
+        if (clamped) {
+            for (int offset = 0; offset <= wid.length; ++offset) {
+                if (wid[offset] > mWidth) {
+                    wid[offset] = mWidth;
+                }
+            }
+        }
+        int left = getParagraphLeft(line);
+        int right = getParagraphRight(line);
+
+        int lineStartPos = getLineStartPos(line, left, right);
+        float[] horizontal = new float[end - start + 1];
+        for (int offset = 0; offset < horizontal.length; ++offset) {
+            horizontal[offset] = lineStartPos + wid[offset];
+        }
+        return horizontal;
+    }
+
+    /**
      * Get the leftmost position that should be exposed for horizontal
      * scrolling on the specified line.
      */
@@ -1362,6 +1479,8 @@
         // XXX: we don't care about tabs as we just use TextLine#getOffsetToLeftRightOf here.
         tl.set(mPaint, mText, lineStartOffset, lineEndOffset, getParagraphDirection(line), dirs,
                 false, null);
+        final HorizontalMeasurementProvider horizontal =
+                new HorizontalMeasurementProvider(line, primary);
 
         final int max;
         if (line == getLineCount() - 1) {
@@ -1371,7 +1490,7 @@
                     !isRtlCharAt(lineEndOffset - 1)) + lineStartOffset;
         }
         int best = lineStartOffset;
-        float bestdist = Math.abs(getHorizontal(best, primary) - horiz);
+        float bestdist = Math.abs(horizontal.get(lineStartOffset) - horiz);
 
         for (int i = 0; i < dirs.mDirections.length; i += 2) {
             int here = lineStartOffset + dirs.mDirections[i];
@@ -1387,7 +1506,7 @@
                 guess = (high + low) / 2;
                 int adguess = getOffsetAtStartOf(guess);
 
-                if (getHorizontal(adguess, primary) * swap >= horiz * swap) {
+                if (horizontal.get(adguess) * swap >= horiz * swap) {
                     high = guess;
                 } else {
                     low = guess;
@@ -1401,9 +1520,9 @@
                 int aft = tl.getOffsetToLeftRightOf(low - lineStartOffset, isRtl) + lineStartOffset;
                 low = tl.getOffsetToLeftRightOf(aft - lineStartOffset, !isRtl) + lineStartOffset;
                 if (low >= here && low < there) {
-                    float dist = Math.abs(getHorizontal(low, primary) - horiz);
+                    float dist = Math.abs(horizontal.get(low) - horiz);
                     if (aft < there) {
-                        float other = Math.abs(getHorizontal(aft, primary) - horiz);
+                        float other = Math.abs(horizontal.get(aft) - horiz);
 
                         if (other < dist) {
                             dist = other;
@@ -1418,7 +1537,7 @@
                 }
             }
 
-            float dist = Math.abs(getHorizontal(here, primary) - horiz);
+            float dist = Math.abs(horizontal.get(here) - horiz);
 
             if (dist < bestdist) {
                 bestdist = dist;
@@ -1426,7 +1545,7 @@
             }
         }
 
-        float dist = Math.abs(getHorizontal(max, primary) - horiz);
+        float dist = Math.abs(horizontal.get(max) - horiz);
 
         if (dist <= bestdist) {
             best = max;
@@ -1437,6 +1556,46 @@
     }
 
     /**
+     * Responds to #getHorizontal queries, by selecting the better strategy between:
+     * - calling #getHorizontal explicitly for each query
+     * - precomputing all #getHorizontal measurements, and responding to any query in constant time
+     * The first strategy is used for LTR-only text, while the second is used for all other cases.
+     * The class is currently only used in #getOffsetForHorizontal, so reuse with care in other
+     * contexts.
+     */
+    private class HorizontalMeasurementProvider {
+        private final int mLine;
+        private final boolean mPrimary;
+
+        private float[] mHorizontals;
+        private int mLineStartOffset;
+
+        HorizontalMeasurementProvider(final int line, final boolean primary) {
+            mLine = line;
+            mPrimary = primary;
+            init();
+        }
+
+        private void init() {
+            final Directions dirs = getLineDirections(mLine);
+            if (dirs == DIRS_ALL_LEFT_TO_RIGHT) {
+                return;
+            }
+
+            mHorizontals = getLineHorizontals(mLine, false, mPrimary);
+            mLineStartOffset = getLineStart(mLine);
+        }
+
+        float get(final int offset) {
+            if (mHorizontals == null) {
+                return getHorizontal(offset, mPrimary);
+            } else {
+                return mHorizontals[offset - mLineStartOffset];
+            }
+        }
+    }
+
+    /**
      * Return the text offset after the last character on the specified line.
      */
     public final int getLineEnd(int line) {
diff --git a/core/java/android/text/TextLine.java b/core/java/android/text/TextLine.java
index 64365fa..b9f93e5 100644
--- a/core/java/android/text/TextLine.java
+++ b/core/java/android/text/TextLine.java
@@ -388,6 +388,99 @@
     }
 
     /**
+     * @see #measure(int, boolean, FontMetricsInt)
+     * @return The measure results for all possible offsets
+     */
+    @VisibleForTesting
+    public float[] measureAllOffsets(boolean[] trailing, FontMetricsInt fmi) {
+        float[] measurement = new float[mLen + 1];
+
+        int[] target = new int[mLen + 1];
+        for (int offset = 0; offset < target.length; ++offset) {
+            target[offset] = trailing[offset] ? offset - 1 : offset;
+        }
+        if (target[0] < 0) {
+            measurement[0] = 0;
+        }
+
+        float h = 0;
+
+        if (!mHasTabs) {
+            if (mDirections == Layout.DIRS_ALL_LEFT_TO_RIGHT) {
+                for (int offset = 0; offset <= mLen; ++offset) {
+                    measurement[offset] = measureRun(0, offset, mLen, false, fmi);
+                }
+                return measurement;
+            }
+            if (mDirections == Layout.DIRS_ALL_RIGHT_TO_LEFT) {
+                for (int offset = 0; offset <= mLen; ++offset) {
+                    measurement[offset] = measureRun(0, offset, mLen, true, fmi);
+                }
+                return measurement;
+            }
+        }
+
+        char[] chars = mChars;
+        int[] runs = mDirections.mDirections;
+        for (int i = 0; i < runs.length; i += 2) {
+            int runStart = runs[i];
+            int runLimit = runStart + (runs[i + 1] & Layout.RUN_LENGTH_MASK);
+            if (runLimit > mLen) {
+                runLimit = mLen;
+            }
+            boolean runIsRtl = (runs[i + 1] & Layout.RUN_RTL_FLAG) != 0;
+
+            int segstart = runStart;
+            for (int j = mHasTabs ? runStart : runLimit; j <= runLimit; ++j) {
+                int codept = 0;
+                if (mHasTabs && j < runLimit) {
+                    codept = chars[j];
+                    if (codept >= 0xD800 && codept < 0xDC00 && j + 1 < runLimit) {
+                        codept = Character.codePointAt(chars, j);
+                        if (codept > 0xFFFF) {
+                            ++j;
+                            continue;
+                        }
+                    }
+                }
+
+                if (j == runLimit || codept == '\t') {
+                    float oldh = h;
+                    boolean advance = (mDir == Layout.DIR_RIGHT_TO_LEFT) == runIsRtl;
+                    float w = measureRun(segstart, j, j, runIsRtl, fmi);
+                    h += advance ? w : -w;
+
+                    float baseh = advance ? oldh : h;
+                    FontMetricsInt crtfmi = advance ? fmi : null;
+                    for (int offset = segstart; offset <= j && offset <= mLen; ++offset) {
+                        if (target[offset] >= segstart && target[offset] < j) {
+                            measurement[offset] =
+                                    baseh + measureRun(segstart, offset, j, runIsRtl, crtfmi);
+                        }
+                    }
+
+                    if (codept == '\t') {
+                        if (target[j] == j) {
+                            measurement[j] = h;
+                        }
+                        h = mDir * nextTab(h * mDir);
+                        if (target[j + 1] == j) {
+                            measurement[j + 1] =  h;
+                        }
+                    }
+
+                    segstart = j + 1;
+                }
+            }
+        }
+        if (target[mLen] == mLen) {
+            measurement[mLen] = h;
+        }
+
+        return measurement;
+    }
+
+    /**
      * Draws a unidirectional (but possibly multi-styled) run of text.
      *
      *
@@ -824,6 +917,9 @@
                 wp.setColor(previousColor);
             }
 
+            drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
+                    leftX, y + wp.baselineShift);
+
             if (numDecorations != 0) {
                 for (int i = 0; i < numDecorations; i++) {
                     final DecorationInfo info = decorations.get(i);
@@ -866,8 +962,6 @@
                 }
             }
 
-            drawTextRun(c, wp, start, end, contextStart, contextEnd, runIsRtl,
-                    leftX, y + wp.baselineShift);
         }
 
         return runIsRtl ? -totalWidth : totalWidth;
diff --git a/core/java/android/util/FeatureFlagUtils.java b/core/java/android/util/FeatureFlagUtils.java
index 9371319..80de99e 100644
--- a/core/java/android/util/FeatureFlagUtils.java
+++ b/core/java/android/util/FeatureFlagUtils.java
@@ -42,6 +42,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", "true");
     }
 
     /**
diff --git a/core/java/android/view/KeyEvent.java b/core/java/android/view/KeyEvent.java
index 378bb1a..dd5abaa 100644
--- a/core/java/android/view/KeyEvent.java
+++ b/core/java/android/view/KeyEvent.java
@@ -16,6 +16,7 @@
 
 package android.view;
 
+import android.annotation.NonNull;
 import android.annotation.TestApi;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -810,7 +811,12 @@
     /** Key code constant: Refresh key. */
     public static final int KEYCODE_REFRESH = 285;
 
-    private static final int LAST_KEYCODE = KEYCODE_REFRESH;
+    /**
+     * Integer value of the last KEYCODE. Increases as new keycodes are added to KeyEvent.
+     * @hide
+     */
+    @TestApi
+    public static final int LAST_KEYCODE = KEYCODE_REFRESH;
 
     // NOTE: If you add a new keycode here you must also add it to:
     //  isSystem()
@@ -2889,25 +2895,34 @@
 
     /**
      * Gets a keycode by its symbolic name such as "KEYCODE_A" or an equivalent
-     * numeric constant such as "1001".
+     * numeric constant such as "29". For symbolic names,
+     * starting in {@link android.os.Build.VERSION_CODES#Q} the prefix "KEYCODE_" is optional.
      *
      * @param symbolicName The symbolic name of the keycode.
      * @return The keycode or {@link #KEYCODE_UNKNOWN} if not found.
      * @see #keycodeToString(int)
      */
-    public static int keyCodeFromString(String symbolicName) {
-        if (symbolicName.startsWith(LABEL_PREFIX)) {
-            symbolicName = symbolicName.substring(LABEL_PREFIX.length());
-            int keyCode = nativeKeyCodeFromString(symbolicName);
-            if (keyCode > 0) {
+    public static int keyCodeFromString(@NonNull String symbolicName) {
+        try {
+            int keyCode = Integer.parseInt(symbolicName);
+            if (keyCodeIsValid(keyCode)) {
                 return keyCode;
             }
-        }
-        try {
-            return Integer.parseInt(symbolicName, 10);
         } catch (NumberFormatException ex) {
-            return KEYCODE_UNKNOWN;
         }
+
+        if (symbolicName.startsWith(LABEL_PREFIX)) {
+            symbolicName = symbolicName.substring(LABEL_PREFIX.length());
+        }
+        int keyCode = nativeKeyCodeFromString(symbolicName);
+        if (keyCodeIsValid(keyCode)) {
+            return keyCode;
+        }
+        return KEYCODE_UNKNOWN;
+    }
+
+    private static boolean keyCodeIsValid(int keyCode) {
+        return keyCode >= KEYCODE_UNKNOWN && keyCode <= LAST_KEYCODE;
     }
 
     /**
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 364a4a5..2b0d81c 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1626,6 +1626,8 @@
                         contentInsets.top + outsets.top, contentInsets.right + outsets.right,
                         contentInsets.bottom + outsets.bottom);
             }
+            contentInsets = ensureInsetsNonNegative(contentInsets, "content");
+            stableInsets = ensureInsetsNonNegative(stableInsets, "stable");
             mLastWindowInsets = new WindowInsets(contentInsets,
                     null /* windowDecorInsets */, stableInsets,
                     mContext.getResources().getConfiguration().isScreenRound(),
@@ -1634,6 +1636,17 @@
         return mLastWindowInsets;
     }
 
+    private Rect ensureInsetsNonNegative(Rect insets, String kind) {
+        if (insets.left < 0  || insets.top < 0  || insets.right < 0  || insets.bottom < 0) {
+            Log.wtf(mTag, "Negative " + kind + "Insets: " + insets + ", mFirst=" + mFirst);
+            return new Rect(Math.max(0, insets.left),
+                    Math.max(0, insets.top),
+                    Math.max(0, insets.right),
+                    Math.max(0, insets.bottom));
+        }
+        return insets;
+    }
+
     void dispatchApplyInsets(View host) {
         WindowInsets insets = getWindowInsets(true /* forceConstruct */);
         final boolean dispatchCutout = (mWindowAttributes.layoutInDisplayCutoutMode
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 4c7dc11..7555fff 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1899,10 +1899,20 @@
     }
 
     private LogMaker newLog(int category) {
-        return new LogMaker(category)
-                .setPackageName(mContext.getPackageName())
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE,
-                        isCompatibilityModeEnabledLocked() ? 1 : 0);
+        final LogMaker log = new LogMaker(category)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, mSessionId);
+
+        if (isCompatibilityModeEnabledLocked()) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+        }
+        final AutofillClient client = getClient();
+        if (client == null) {
+            // Client should never be null here, but it doesn't hurt to check...
+            log.setPackageName(mContext.getPackageName());
+        } else {
+            log.setComponentName(client.autofillClientGetComponentName());
+        }
+        return log;
     }
 
     /**
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/android/webkit/SslErrorHandler.java b/core/java/android/webkit/SslErrorHandler.java
index 537065d..1d5c6f1 100644
--- a/core/java/android/webkit/SslErrorHandler.java
+++ b/core/java/android/webkit/SslErrorHandler.java
@@ -36,6 +36,10 @@
 
     /**
      * Proceed with the SSL certificate.
+     * <p>
+     * It is not recommended to proceed past SSL errors and this method should
+     * generally not be used; see {@link WebViewClient#onReceivedSslError} for
+     * more information.
      */
     public void proceed() {}
 
diff --git a/core/java/android/webkit/WebChromeClient.java b/core/java/android/webkit/WebChromeClient.java
index 4aa1c4a..95fe963 100644
--- a/core/java/android/webkit/WebChromeClient.java
+++ b/core/java/android/webkit/WebChromeClient.java
@@ -113,6 +113,20 @@
      * the new WebView as an argument. If the host application chooses not to
      * honor the request, it should return {@code false} from this method. The default
      * implementation of this method does nothing and hence returns {@code false}.
+     * <p>
+     * Applications should typically not allow windows to be created when the
+     * {@code isUserGesture} flag is false, as this may be an unwanted popup.
+     * <p>
+     * Applications should be careful how they display the new window: don't simply
+     * overlay it over the existing WebView as this may mislead the user about which
+     * site they are viewing. If your application displays the URL of the main page,
+     * make sure to also display the URL of the new window in a similar fashion. If
+     * your application does not display URLs, consider disallowing the creation of
+     * new windows entirely.
+     * <p class="note"><b>Note:</b> There is no trustworthy way to tell which page
+     * requested the new window: the request might originate from a third-party iframe
+     * inside the WebView.
+     *
      * @param view The WebView from which the request for a new window
      *             originated.
      * @param isDialog {@code true} if the new window should be a dialog, rather than
@@ -149,6 +163,11 @@
      * from the view system if necessary. At this point, WebCore has stopped
      * any loading in this window and has removed any cross-scripting ability
      * in javascript.
+     * <p>
+     * As with {@link #onCreateWindow}, the application should ensure that any
+     * URL or security indicator displayed is updated so that the user can tell
+     * that the page they were interacting with has been closed.
+     *
      * @param window The WebView that needs to be closed.
      */
     public void onCloseWindow(WebView window) {}
diff --git a/core/java/android/webkit/WebView.java b/core/java/android/webkit/WebView.java
index bd000f6..4eb85ac 100644
--- a/core/java/android/webkit/WebView.java
+++ b/core/java/android/webkit/WebView.java
@@ -1019,11 +1019,21 @@
      * If {@code null}, defaults to 'text/html'.
      * <p>
      * The 'data' scheme URL formed by this method uses the default US-ASCII
-     * charset. If you need need to set a different charset, you should form a
+     * charset. If you need to set a different charset, you should form a
      * 'data' scheme URL which explicitly specifies a charset parameter in the
      * mediatype portion of the URL and call {@link #loadUrl(String)} instead.
      * Note that the charset obtained from the mediatype portion of a data URL
      * always overrides that specified in the HTML or XML document itself.
+     * <p>
+     * Content loaded using this method will have a {@code window.origin} value
+     * of {@code "null"}. This must not be considered to be a trusted origin
+     * by the application or by any JavaScript code running inside the WebView
+     * (for example, event sources in DOM event handlers or web messages),
+     * because malicious content can also create frames with a null origin. If
+     * you need to identify the main frame's origin in a trustworthy way, you
+     * should use {@link #loadDataWithBaseURL(String,String,String,String,String)
+     * loadDataWithBaseURL()} with a valid HTTP or HTTPS base URL to set the
+     * origin.
      *
      * @param data a String of data in the given encoding
      * @param mimeType the MIME type of the data, e.g. 'text/html'.
@@ -1057,6 +1067,15 @@
      * <p>
      * Note that the baseUrl is sent in the 'Referer' HTTP header when
      * requesting subresources (images, etc.) of the page loaded using this method.
+     * <p>
+     * If a valid HTTP or HTTPS base URL is not specified in {@code baseUrl}, then
+     * content loaded using this method will have a {@code window.origin} value
+     * of {@code "null"}. This must not be considered to be a trusted origin
+     * by the application or by any JavaScript code running inside the WebView
+     * (for example, event sources in DOM event handlers or web messages),
+     * because malicious content can also create frames with a null origin. If
+     * you need to identify the main frame's origin in a trustworthy way, you
+     * should use a valid HTTP or HTTPS base URL to set the origin.
      *
      * @param baseUrl the URL to use as the page's base URL. If {@code null} defaults to
      *                'about:blank'.
@@ -2053,6 +2072,13 @@
      * <p>
      * A target origin can be set as a wildcard ("*"). However this is not recommended.
      * See the page above for security issues.
+     * <p>
+     * Content loaded via {@link #loadData(String,String,String)} will not have a
+     * valid origin, and thus cannot be sent messages securely. If you need to send
+     * messages using this function, you should use
+     * {@link #loadDataWithBaseURL(String,String,String,String,String)} with a valid
+     * HTTP or HTTPS {@code baseUrl} to define a valid origin that can be used for
+     * messaging.
      *
      * @param message the WebMessage
      * @param targetOrigin the target origin.
diff --git a/core/java/android/webkit/WebViewClient.java b/core/java/android/webkit/WebViewClient.java
index 6df1655..f686b66 100644
--- a/core/java/android/webkit/WebViewClient.java
+++ b/core/java/android/webkit/WebViewClient.java
@@ -368,6 +368,15 @@
      * handler.proceed(). Note that the decision may be retained for use in
      * response to future SSL errors. The default behavior is to cancel the
      * load.
+     * <p>
+     * Applications are advised not to prompt the user about SSL errors, as
+     * the user is unlikely to be able to make an informed security decision
+     * and WebView does not provide any UI for showing the details of the
+     * error in a meaningful way.
+     * <p>
+     * Application overrides of this method may display custom error pages or
+     * silently log issues, but it is strongly recommended to always call
+     * handler.cancel() and never allow proceeding past errors.
      *
      * @param view The WebView that is initiating the callback.
      * @param handler An SslErrorHandler object that will handle the user's
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index d22b1e6..6cb0eaa 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -285,10 +285,14 @@
         final Layout layout = mTextView.getLayout();
 
         final Runnable onAnimationEndCallback = () -> {
-            if (result.mStart >= 0 && result.mEnd <= getText(mTextView).length()
+            final SelectionResult startSelectionResult;
+            if (result != null && result.mStart >= 0 && result.mEnd <= getText(mTextView).length()
                     && result.mStart <= result.mEnd) {
-                startSelectionActionMode(result);
+                startSelectionResult = result;
+            } else {
+                startSelectionResult = null;
             }
+            startSelectionActionMode(startSelectionResult);
         };
         // TODO do not trigger the animation if the change included only non-printable characters
         final boolean didSelectionChange =
diff --git a/core/java/com/android/internal/app/AssistUtils.java b/core/java/com/android/internal/app/AssistUtils.java
index 2940079..9171959 100644
--- a/core/java/com/android/internal/app/AssistUtils.java
+++ b/core/java/com/android/internal/app/AssistUtils.java
@@ -156,9 +156,12 @@
         if (activeServiceSupportsAssistGesture()) {
             return getActiveServiceComponentName();
         }
-
-        Intent intent = ((SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE))
-                .getAssistIntent(false);
+        final SearchManager searchManager =
+            (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
+        if (searchManager == null) {
+            return null;
+        }
+        final Intent intent = searchManager.getAssistIntent(false);
         PackageManager pm = mContext.getPackageManager();
         ResolveInfo info = pm.resolveActivityAsUser(intent, PackageManager.MATCH_DEFAULT_ONLY,
                 userId);
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 97043c7..4f567d2 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -21,6 +21,7 @@
 import android.animation.ObjectAnimator;
 import android.annotation.NonNull;
 import android.app.Activity;
+import android.app.ActivityManager;
 import android.app.usage.UsageStatsManager;
 import android.content.ComponentName;
 import android.content.Context;
@@ -75,6 +76,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.app.ResolverActivity;
 import com.android.internal.app.ResolverActivity.TargetInfo;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
@@ -931,7 +933,7 @@
         public static final int TARGET_SERVICE = 1;
         public static final int TARGET_STANDARD = 2;
 
-        private static final int MAX_SERVICE_TARGETS = 8;
+        private static final int MAX_SERVICE_TARGETS = 4;
         private static final int MAX_TARGETS_PER_SERVICE = 4;
 
         private final List<ChooserTargetInfo> mServiceTargets = new ArrayList<>();
@@ -1022,6 +1024,11 @@
 
         @Override
         public void onListRebuilt() {
+            // don't support direct share on low ram devices
+            if (ActivityManager.isLowRamDeviceStatic()) {
+                return;
+            }
+
             if (mServiceTargets != null) {
                 pruneServiceTargets();
             }
@@ -1183,123 +1190,20 @@
         }
     }
 
-    static class RowScale {
-        private static final int DURATION = 400;
-
-        float mScale;
-        ChooserRowAdapter mAdapter;
-        private final ObjectAnimator mAnimator;
-
-        public static final FloatProperty<RowScale> PROPERTY =
-                new FloatProperty<RowScale>("scale") {
-            @Override
-            public void setValue(RowScale object, float value) {
-                object.mScale = value;
-                object.mAdapter.notifyDataSetChanged();
-            }
-
-            @Override
-            public Float get(RowScale object) {
-                return object.mScale;
-            }
-        };
-
-        public RowScale(@NonNull ChooserRowAdapter adapter, float from, float to) {
-            mAdapter = adapter;
-            mScale = from;
-            if (from == to) {
-                mAnimator = null;
-                return;
-            }
-
-            mAnimator = ObjectAnimator.ofFloat(this, PROPERTY, from, to)
-                .setDuration(DURATION);
-            mAnimator.addListener(new AnimatorListenerAdapter() {
-                @Override
-                public void onAnimationStart(Animator animation) {
-                    mAdapter.onAnimationStart();
-                }
-                @Override
-                public void onAnimationEnd(Animator animation) {
-                    mAdapter.onAnimationEnd();
-                }
-            });
-        }
-
-        public RowScale setInterpolator(Interpolator interpolator) {
-            if (mAnimator != null) {
-                mAnimator.setInterpolator(interpolator);
-            }
-            return this;
-        }
-
-        public float get() {
-            return mScale;
-        }
-
-        public void startAnimation() {
-            if (mAnimator != null) {
-                mAnimator.start();
-            }
-        }
-
-        public void cancelAnimation() {
-            if (mAnimator != null) {
-                mAnimator.cancel();
-            }
-        }
-    }
-
     class ChooserRowAdapter extends BaseAdapter {
         private ChooserListAdapter mChooserListAdapter;
         private final LayoutInflater mLayoutInflater;
         private final int mColumnCount = 4;
-        private RowScale[] mServiceTargetScale;
-        private final Interpolator mInterpolator;
         private int mAnimationCount = 0;
 
         public ChooserRowAdapter(ChooserListAdapter wrappedAdapter) {
             mChooserListAdapter = wrappedAdapter;
             mLayoutInflater = LayoutInflater.from(ChooserActivity.this);
 
-            mInterpolator = AnimationUtils.loadInterpolator(ChooserActivity.this,
-                    android.R.interpolator.decelerate_quint);
-
             wrappedAdapter.registerDataSetObserver(new DataSetObserver() {
                 @Override
                 public void onChanged() {
                     super.onChanged();
-                    final int rcount = getServiceTargetRowCount();
-                    if (mServiceTargetScale == null
-                            || mServiceTargetScale.length != rcount) {
-                        RowScale[] old = mServiceTargetScale;
-                        int oldRCount = old != null ? old.length : 0;
-                        mServiceTargetScale = new RowScale[rcount];
-                        if (old != null && rcount > 0) {
-                            System.arraycopy(old, 0, mServiceTargetScale, 0,
-                                    Math.min(old.length, rcount));
-                        }
-
-                        for (int i = rcount; i < oldRCount; i++) {
-                            old[i].cancelAnimation();
-                        }
-
-                        for (int i = oldRCount; i < rcount; i++) {
-                            final RowScale rs = new RowScale(ChooserRowAdapter.this, 0.f, 1.f)
-                                    .setInterpolator(mInterpolator);
-                            mServiceTargetScale[i] = rs;
-                        }
-
-                        // Start the animations in a separate loop.
-                        // The process of starting animations will result in
-                        // binding views to set up initial values, and we must
-                        // have ALL of the new RowScale objects created above before
-                        // we get started.
-                        for (int i = oldRCount; i < rcount; i++) {
-                            mServiceTargetScale[i].startAnimation();
-                        }
-                    }
-
                     notifyDataSetChanged();
                 }
 
@@ -1307,39 +1211,10 @@
                 public void onInvalidated() {
                     super.onInvalidated();
                     notifyDataSetInvalidated();
-                    if (mServiceTargetScale != null) {
-                        for (RowScale rs : mServiceTargetScale) {
-                            rs.cancelAnimation();
-                        }
-                    }
                 }
             });
         }
 
-        private float getRowScale(int rowPosition) {
-            final int start = getCallerTargetRowCount();
-            final int end = start + getServiceTargetRowCount();
-            if (rowPosition >= start && rowPosition < end) {
-                return mServiceTargetScale[rowPosition - start].get();
-            }
-            return 1.f;
-        }
-
-        public void onAnimationStart() {
-            final boolean lock = mAnimationCount == 0;
-            mAnimationCount++;
-            if (lock) {
-                mResolverDrawerLayout.setDismissLocked(true);
-            }
-        }
-
-        public void onAnimationEnd() {
-            mAnimationCount--;
-            if (mAnimationCount == 0) {
-                mResolverDrawerLayout.setDismissLocked(false);
-            }
-        }
-
         @Override
         public int getCount() {
             return (int) (
@@ -1354,9 +1229,9 @@
                     (float) mChooserListAdapter.getCallerTargetCount() / mColumnCount);
         }
 
+        // There can be at most one row of service targets.
         public int getServiceTargetRowCount() {
-            return (int) Math.ceil(
-                    (float) mChooserListAdapter.getServiceTargetCount() / mColumnCount);
+            return (int) mChooserListAdapter.getServiceTargetCount() == 0 ? 0 : 1;
         }
 
         @Override
@@ -1479,8 +1354,7 @@
             }
 
             final int oldHeight = holder.row.getLayoutParams().height;
-            holder.row.getLayoutParams().height = Math.max(1,
-                    (int) (holder.measuredRowHeight * getRowScale(rowPosition)));
+            holder.row.getLayoutParams().height = Math.max(1, holder.measuredRowHeight);
             if (holder.row.getLayoutParams().height != oldHeight) {
                 holder.row.requestLayout();
             }
@@ -1722,7 +1596,7 @@
                 final View v = mChooserRowAdapter.getView(pos, mCachedView, mListView);
                 int height = ((RowViewHolder) (v.getTag())).measuredRowHeight;
 
-                offset += (int) (height * mChooserRowAdapter.getRowScale(pos));
+                offset += (int) (height);
 
                 if (vt >= 0) {
                     mCachedViewType = vt;
diff --git a/core/java/com/android/internal/app/ColorDisplayController.java b/core/java/com/android/internal/app/ColorDisplayController.java
index 6cc964b..ba6cf26 100644
--- a/core/java/com/android/internal/app/ColorDisplayController.java
+++ b/core/java/com/android/internal/app/ColorDisplayController.java
@@ -335,7 +335,7 @@
         if (colorTemperature == -1) {
             if (DEBUG) {
                 Slog.d(TAG, "Using default value for setting: "
-                    + Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE);
+                        + Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE);
             }
             colorTemperature = getDefaultColorTemperature();
         }
@@ -358,7 +358,7 @@
      */
     public boolean setColorTemperature(int colorTemperature) {
         return Secure.putIntForUser(mContext.getContentResolver(),
-            Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
+                Secure.NIGHT_DISPLAY_COLOR_TEMPERATURE, colorTemperature, mUserId);
     }
 
     /**
@@ -367,10 +367,10 @@
      * See com.android.server.display.DisplayTransformManager.
      */
     private @ColorMode int getCurrentColorModeFromSystemProperties() {
-        int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
+        final int displayColorSetting = SystemProperties.getInt("persist.sys.sf.native_mode", 0);
         if (displayColorSetting == 0) {
             return "1.0".equals(SystemProperties.get("persist.sys.sf.color_saturation"))
-                ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
+                    ? COLOR_MODE_NATURAL : COLOR_MODE_BOOSTED;
         } else if (displayColorSetting == 1) {
             return COLOR_MODE_SATURATED;
         } else if (displayColorSetting == 2) {
@@ -381,16 +381,13 @@
     }
 
     private boolean isColorModeAvailable(@ColorMode int colorMode) {
-        // SATURATED is always allowed
-        if (colorMode == COLOR_MODE_SATURATED) {
-            return true;
-        }
-
         final int[] availableColorModes = mContext.getResources().getIntArray(
                 R.array.config_availableColorModes);
-        for (int mode : availableColorModes) {
-            if (mode == colorMode) {
-                return true;
+        if (availableColorModes != null) {
+            for (int mode : availableColorModes) {
+                if (mode == colorMode) {
+                    return true;
+                }
             }
         }
         return false;
@@ -401,14 +398,18 @@
      */
     public int getColorMode() {
         if (getAccessibilityTransformActivated()) {
-            return COLOR_MODE_SATURATED;
+            if (isColorModeAvailable(COLOR_MODE_SATURATED)) {
+                return COLOR_MODE_SATURATED;
+            } else if (isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
+                return COLOR_MODE_AUTOMATIC;
+            }
         }
 
         int colorMode = System.getIntForUser(mContext.getContentResolver(),
-            System.DISPLAY_COLOR_MODE, -1, mUserId);
+                System.DISPLAY_COLOR_MODE, -1, mUserId);
         if (colorMode == -1) {
-            // There still might be a legacy system property controlling color mode that we need to
-            // respect.
+            // There might be a system property controlling color mode that we need to respect; if
+            // not, this will set a suitable default.
             colorMode = getCurrentColorModeFromSystemProperties();
         }
 
@@ -418,10 +419,13 @@
             if (colorMode == COLOR_MODE_BOOSTED && isColorModeAvailable(COLOR_MODE_NATURAL)) {
                 colorMode = COLOR_MODE_NATURAL;
             } else if (colorMode == COLOR_MODE_SATURATED
-                && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
+                    && isColorModeAvailable(COLOR_MODE_AUTOMATIC)) {
                 colorMode = COLOR_MODE_AUTOMATIC;
-            } else {
+            } else if (colorMode == COLOR_MODE_AUTOMATIC
+                    && isColorModeAvailable(COLOR_MODE_SATURATED)) {
                 colorMode = COLOR_MODE_SATURATED;
+            } else {
+                colorMode = -1;
             }
         }
 
diff --git a/core/java/com/android/internal/app/SuspendedAppActivity.java b/core/java/com/android/internal/app/SuspendedAppActivity.java
index f42a195..a8edfb6 100644
--- a/core/java/com/android/internal/app/SuspendedAppActivity.java
+++ b/core/java/com/android/internal/app/SuspendedAppActivity.java
@@ -60,7 +60,7 @@
         if (resolvedInfo != null && resolvedInfo.activityInfo != null
                 && requiredPermission.equals(resolvedInfo.activityInfo.permission)) {
             moreDetailsIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, suspendedPackage)
-                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                    .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);
             return moreDetailsIntent;
         }
         return null;
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/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index f537e3e..12761b9 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -150,6 +150,11 @@
             return null;
         }
 
+        if (parsedArgs.pidQuery) {
+            handlePidQuery();
+            return null;
+        }
+
         if (parsedArgs.preloadDefault) {
             handlePreload();
             return null;
@@ -271,6 +276,17 @@
         }
     }
 
+    private void handlePidQuery() {
+        try {
+            String pidString = String.valueOf(Process.myPid());
+            final byte[] pidStringBytes = pidString.getBytes(StandardCharsets.US_ASCII);
+            mSocketOutStream.writeInt(pidStringBytes.length);
+            mSocketOutStream.write(pidStringBytes);
+        } catch (IOException ioe) {
+            throw new IllegalStateException("Error writing to command socket", ioe);
+        }
+    }
+
     /**
      * Preloads resources if the zygote is in lazily preload mode. Writes the result of the
      * preload operation; {@code 0} when a preload was initiated due to this request and {@code 1}
@@ -469,6 +485,11 @@
         boolean startChildZygote;
 
         /**
+         * Whether the current arguments constitute a request for the zygote's PID.
+         */
+        boolean pidQuery;
+
+        /**
          * Exemptions from API blacklisting. These are sent to the pre-forked zygote at boot time,
          * or when they change, via --set-api-blacklist-exemptions.
          */
@@ -622,6 +643,8 @@
                     mountExternal = Zygote.MOUNT_EXTERNAL_WRITE;
                 } else if (arg.equals("--query-abi-list")) {
                     abiListQuery = true;
+                } else if (arg.equals("--get-pid")) {
+                    pidQuery = true;
                 } else if (arg.startsWith("--instruction-set=")) {
                     instructionSet = arg.substring(arg.indexOf('=') + 1);
                 } else if (arg.startsWith("--app-data-dir=")) {
@@ -656,7 +679,7 @@
                 }
             }
 
-            if (abiListQuery) {
+            if (abiListQuery || pidQuery) {
                 if (args.length - curArg > 0) {
                     throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
                 }
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index 7116f3a..c9a9161 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -100,7 +100,6 @@
         super.onFinishInflate();
         mMessageContainer = findViewById(R.id.group_message_container);
         mSenderName = findViewById(R.id.message_name);
-        mSenderName.addOnLayoutChangeListener(MessagingLayout.MESSAGING_PROPERTY_ANIMATOR);
         mAvatarView = findViewById(R.id.message_icon);
         mImageContainer = findViewById(R.id.messaging_group_icon_container);
         mSendingSpinner = findViewById(R.id.messaging_group_sending_progress);
@@ -190,71 +189,66 @@
     }
 
     public void removeMessage(MessagingMessage messagingMessage) {
-        ViewGroup messageParent = (ViewGroup) messagingMessage.getView().getParent();
-        messageParent.removeView(messagingMessage.getView());
+        View view = messagingMessage.getView();
+        boolean wasShown = view.isShown();
+        ViewGroup messageParent = (ViewGroup) view.getParent();
+        if (messageParent == null) {
+            return;
+        }
+        messageParent.removeView(view);
         Runnable recycleRunnable = () -> {
-            messageParent.removeTransientView(messagingMessage.getView());
+            messageParent.removeTransientView(view);
             messagingMessage.recycle();
-            if (mMessageContainer.getChildCount() == 0
-                    && mMessageContainer.getTransientViewCount() == 0
-                    && mImageContainer.getChildCount() == 0) {
-                ViewParent parent = getParent();
-                if (parent instanceof ViewGroup) {
-                    ((ViewGroup) parent).removeView(MessagingGroup.this);
-                }
-                setAvatar(null);
-                mAvatarView.setAlpha(1.0f);
-                mAvatarView.setTranslationY(0.0f);
-                mSenderName.setAlpha(1.0f);
-                mSenderName.setTranslationY(0.0f);
-                sInstancePool.release(MessagingGroup.this);
-            }
         };
-        if (isShown()) {
-            messageParent.addTransientView(messagingMessage.getView(), 0);
-            performRemoveAnimation(messagingMessage.getView(), recycleRunnable);
-            if (mMessageContainer.getChildCount() == 0
-                    && mImageContainer.getChildCount() == 0) {
-                removeGroupAnimated(null);
-            }
+        if (wasShown && !MessagingLinearLayout.isGone(view)) {
+            messageParent.addTransientView(view, 0);
+            performRemoveAnimation(view, recycleRunnable);
         } else {
             recycleRunnable.run();
         }
-
     }
 
-    private void removeGroupAnimated(Runnable endAction) {
-        performRemoveAnimation(mAvatarView, null);
-        performRemoveAnimation(mSenderName, null);
-        boolean endActionTriggered = false;
-        for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
-            View child = mMessageContainer.getChildAt(i);
-            if (child.getVisibility() == View.GONE) {
-                continue;
-            }
-            final ViewGroup.LayoutParams lp = child.getLayoutParams();
-            if (lp instanceof MessagingLinearLayout.LayoutParams
-                    && ((MessagingLinearLayout.LayoutParams) lp).hide
-                    && !((MessagingLinearLayout.LayoutParams) lp).visibleBefore) {
-                continue;
-            }
-            Runnable childEndAction = endActionTriggered ? null : endAction;
-            performRemoveAnimation(child, childEndAction);
-            endActionTriggered = true;
-        }
+    public void recycle() {
         if (mIsolatedMessage != null) {
-            performRemoveAnimation(mIsolatedMessage, !endActionTriggered ? endAction : null);
-            endActionTriggered = true;
+            mImageContainer.removeView(mIsolatedMessage);
         }
-        if (!endActionTriggered && endAction != null) {
-            endAction.run();
+        for (int i = 0; i < mMessages.size(); i++) {
+            MessagingMessage message = mMessages.get(i);
+            mMessageContainer.removeView(message.getView());
+            message.recycle();
         }
+        setAvatar(null);
+        mAvatarView.setAlpha(1.0f);
+        mAvatarView.setTranslationY(0.0f);
+        mSenderName.setAlpha(1.0f);
+        mSenderName.setTranslationY(0.0f);
+        setAlpha(1.0f);
+        mIsolatedMessage = null;
+        mMessages = null;
+        mAddedMessages.clear();
+        mFirstLayout = true;
+        MessagingPropertyAnimator.recycle(this);
+        sInstancePool.release(MessagingGroup.this);
+    }
+
+    public void removeGroupAnimated(Runnable endAction) {
+        performRemoveAnimation(this, () -> {
+            setAlpha(1.0f);
+            MessagingPropertyAnimator.setToLaidOutPosition(this);
+            if (endAction != null) {
+                endAction.run();
+            }
+        });
     }
 
     public void performRemoveAnimation(View message, Runnable endAction) {
-        MessagingPropertyAnimator.fadeOut(message, endAction);
-        MessagingPropertyAnimator.startLocalTranslationTo(message,
-                (int) (-getHeight() * 0.5f), MessagingLayout.FAST_OUT_LINEAR_IN);
+        performRemoveAnimation(message, -message.getHeight(), endAction);
+    }
+
+    private void performRemoveAnimation(View view, int disappearTranslation, Runnable endAction) {
+        MessagingPropertyAnimator.startLocalTranslationTo(view, disappearTranslation,
+                MessagingLayout.FAST_OUT_LINEAR_IN);
+        MessagingPropertyAnimator.fadeOut(view, endAction);
     }
 
     public CharSequence getSenderName() {
@@ -267,6 +261,11 @@
 
     @Override
     public int getMeasuredType() {
+        if (mIsolatedMessage != null) {
+            // We only want to show one group if we have an inline image, so let's return shortened
+            // to avoid displaying the other ones.
+            return MEASURED_SHORTENED;
+        }
         boolean hasNormal = false;
         for (int i = mMessageContainer.getChildCount() - 1; i >= 0; i--) {
             View child = mMessageContainer.getChildAt(i);
@@ -292,9 +291,6 @@
                 }
             }
         }
-        if (mMessageContainer.getChildCount() == 0 && mIsolatedMessage != null) {
-            return mIsolatedMessage.getMeasuredType();
-        }
         return MEASURED_NORMAL;
     }
 
@@ -337,6 +333,11 @@
         }
     }
 
+    @Override
+    public boolean hasOverlappingRendering() {
+        return false;
+    }
+
     public Icon getAvatarSymbolIfMatching(CharSequence avatarName, String avatarSymbol,
             int layoutColor) {
         if (mAvatarName.equals(avatarName) && mAvatarSymbol.equals(avatarSymbol)
@@ -454,6 +455,7 @@
     protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
         super.onLayout(changed, left, top, right, bottom);
         if (!mAddedMessages.isEmpty()) {
+            final boolean firstLayout = mFirstLayout;
             getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
                 @Override
                 public boolean onPreDraw() {
@@ -462,7 +464,7 @@
                             continue;
                         }
                         MessagingPropertyAnimator.fadeIn(message.getView());
-                        if (!mFirstLayout) {
+                        if (!firstLayout) {
                             MessagingPropertyAnimator.startLocalTranslationFrom(message.getView(),
                                     message.getView().getHeight(),
                                     MessagingLayout.LINEAR_OUT_SLOW_IN);
diff --git a/core/java/com/android/internal/widget/MessagingImageMessage.java b/core/java/com/android/internal/widget/MessagingImageMessage.java
index 9db74e8..607a3a9 100644
--- a/core/java/com/android/internal/widget/MessagingImageMessage.java
+++ b/core/java/com/android/internal/widget/MessagingImageMessage.java
@@ -170,8 +170,6 @@
 
     public void recycle() {
         MessagingMessage.super.recycle();
-        setAlpha(1.0f);
-        setTranslationY(0);
         setImageBitmap(null);
         mDrawable = null;
         sInstancePool.release(this);
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index d468ce3..0fd6109 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -82,7 +82,7 @@
     private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
     private Paint mTextPaint = new Paint();
     private CharSequence mConversationTitle;
-    private Icon mLargeIcon;
+    private Icon mAvatarReplacement;
     private boolean mIsOneToOne;
     private ArrayList<MessagingGroup> mAddedGroups = new ArrayList<>();
     private Person mUser;
@@ -125,8 +125,8 @@
     }
 
     @RemotableViewMethod
-    public void setLargeIcon(Icon icon) {
-        mLargeIcon = icon;
+    public void setAvatarReplacement(Icon icon) {
+        mAvatarReplacement = icon;
     }
 
     @RemotableViewMethod
@@ -180,8 +180,13 @@
         List<MessagingMessage> historicMessages = createMessages(newHistoricMessages,
                 true /* isHistoric */);
         List<MessagingMessage> messages = createMessages(newMessages, false /* isHistoric */);
+
+        ArrayList<MessagingGroup> oldGroups = new ArrayList<>(mGroups);
         addMessagesToGroups(historicMessages, messages, showSpinner);
 
+        // Let's first check which groups were removed altogether and remove them in one animation
+        removeGroups(oldGroups);
+
         // Let's remove the remaining messages
         mMessages.forEach(REMOVE_MESSAGE);
         mHistoricMessages.forEach(REMOVE_MESSAGE);
@@ -193,6 +198,31 @@
         updateTitleAndNamesDisplay();
     }
 
+    private void removeGroups(ArrayList<MessagingGroup> oldGroups) {
+        int size = oldGroups.size();
+        for (int i = 0; i < size; i++) {
+            MessagingGroup group = oldGroups.get(i);
+            if (!mGroups.contains(group)) {
+                List<MessagingMessage> messages = group.getMessages();
+                Runnable endRunnable = () -> {
+                    mMessagingLinearLayout.removeTransientView(group);
+                    group.recycle();
+                };
+
+                boolean wasShown = group.isShown();
+                mMessagingLinearLayout.removeView(group);
+                if (wasShown && !MessagingLinearLayout.isGone(group)) {
+                    mMessagingLinearLayout.addTransientView(group, 0);
+                    group.removeGroupAnimated(endRunnable);
+                } else {
+                    endRunnable.run();
+                }
+                mMessages.removeAll(messages);
+                mHistoricMessages.removeAll(messages);
+            }
+        }
+    }
+
     private void updateTitleAndNamesDisplay() {
         ArrayMap<CharSequence, String> uniqueNames = new ArrayMap<>();
         ArrayMap<Character, CharSequence> uniqueCharacters = new ArrayMap<>();
@@ -228,7 +258,7 @@
             boolean isOwnMessage = group.getSender() == mUser;
             CharSequence senderName = group.getSenderName();
             if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)
-                    || (mIsOneToOne && mLargeIcon != null && !isOwnMessage)) {
+                    || (mIsOneToOne && mAvatarReplacement != null && !isOwnMessage)) {
                 continue;
             }
             String symbol = uniqueNames.get(senderName);
@@ -246,8 +276,8 @@
             if (!group.needsGeneratedAvatar() || TextUtils.isEmpty(senderName)) {
                 continue;
             }
-            if (mIsOneToOne && mLargeIcon != null && group.getSender() != mUser) {
-                group.setAvatar(mLargeIcon);
+            if (mIsOneToOne && mAvatarReplacement != null && group.getSender() != mUser) {
+                group.setAvatar(mAvatarReplacement);
             } else {
                 Icon cachedIcon = cachedAvatars.get(senderName);
                 if (cachedIcon == null) {
diff --git a/core/java/com/android/internal/widget/MessagingLinearLayout.java b/core/java/com/android/internal/widget/MessagingLinearLayout.java
index 991e3e7..64b1f24 100644
--- a/core/java/com/android/internal/widget/MessagingLinearLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLinearLayout.java
@@ -163,15 +163,6 @@
             }
             final LayoutParams lp = (LayoutParams) child.getLayoutParams();
             MessagingChild messagingChild = (MessagingChild) child;
-            if (lp.hide) {
-                if (shown && lp.visibleBefore) {
-                    messagingChild.hideAnimated();
-                }
-                lp.visibleBefore = false;
-                continue;
-            } else {
-                lp.visibleBefore = true;
-            }
 
             final int childWidth = child.getMeasuredWidth();
             final int childHeight = child.getMeasuredHeight();
@@ -182,6 +173,19 @@
             } else {
                 childLeft = paddingLeft + lp.leftMargin;
             }
+            if (lp.hide) {
+                if (shown && lp.visibleBefore) {
+                    // We still want to lay out the child to have great animations
+                    child.layout(childLeft, childTop, childLeft + childWidth,
+                            childTop + lp.lastVisibleHeight);
+                    messagingChild.hideAnimated();
+                }
+                lp.visibleBefore = false;
+                continue;
+            } else {
+                lp.visibleBefore = true;
+                lp.lastVisibleHeight = childHeight;
+            }
 
             if (!first) {
                 childTop += mSpacing;
@@ -228,6 +232,18 @@
         return copy;
     }
 
+    public static boolean isGone(View view) {
+        if (view.getVisibility() == View.GONE) {
+            return true;
+        }
+        final ViewGroup.LayoutParams lp = view.getLayoutParams();
+        if (lp instanceof MessagingLinearLayout.LayoutParams
+                && ((MessagingLinearLayout.LayoutParams) lp).hide) {
+            return true;
+        }
+        return false;
+    }
+
     /**
      * Sets how many lines should be displayed at most
      */
@@ -263,6 +279,7 @@
 
         public boolean hide = false;
         public boolean visibleBefore = false;
+        public int lastVisibleHeight;
 
         public LayoutParams(Context c, AttributeSet attrs) {
             super(c, attrs);
diff --git a/core/java/com/android/internal/widget/MessagingMessage.java b/core/java/com/android/internal/widget/MessagingMessage.java
index ffcb503..74d0aae 100644
--- a/core/java/com/android/internal/widget/MessagingMessage.java
+++ b/core/java/com/android/internal/widget/MessagingMessage.java
@@ -124,8 +124,7 @@
     @Override
     default void hideAnimated() {
         setIsHidingAnimated(true);
-        getGroup().performRemoveAnimation(getState().getHostView(),
-                () -> setIsHidingAnimated(false));
+        getGroup().performRemoveAnimation(getView(), () -> setIsHidingAnimated(false));
     }
 
     default boolean hasOverlappingRendering() {
@@ -133,7 +132,7 @@
     }
 
     default void recycle() {
-        getState().reset();
+        getState().recycle();
     }
 
     default View getView() {
diff --git a/core/java/com/android/internal/widget/MessagingMessageState.java b/core/java/com/android/internal/widget/MessagingMessageState.java
index ac62472..1ba2b51 100644
--- a/core/java/com/android/internal/widget/MessagingMessageState.java
+++ b/core/java/com/android/internal/widget/MessagingMessageState.java
@@ -72,7 +72,10 @@
         return mHostView;
     }
 
-    public void reset() {
+    public void recycle() {
+        mHostView.setAlpha(1.0f);
+        mHostView.setTranslationY(0);
+        MessagingPropertyAnimator.recycle(mHostView);
         mIsHidingAnimated = false;
         mIsHistoric = false;
         mGroup = null;
diff --git a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
index 7c3ab7f..7703cb0 100644
--- a/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
+++ b/core/java/com/android/internal/widget/MessagingPropertyAnimator.java
@@ -31,111 +31,125 @@
  * A listener that automatically starts animations when the layout bounds change.
  */
 public class MessagingPropertyAnimator implements View.OnLayoutChangeListener {
-    static final long APPEAR_ANIMATION_LENGTH = 210;
+    private static final long APPEAR_ANIMATION_LENGTH = 210;
     private static final Interpolator ALPHA_IN = new PathInterpolator(0.4f, 0f, 1f, 1f);
     public static final Interpolator ALPHA_OUT = new PathInterpolator(0f, 0f, 0.8f, 1f);
-    private static final int TAG_LOCAL_TRANSLATION_ANIMATOR = R.id.tag_local_translation_y_animator;
-    private static final int TAG_LOCAL_TRANSLATION_Y = R.id.tag_local_translation_y;
+    private static final int TAG_TOP_ANIMATOR = R.id.tag_top_animator;
+    private static final int TAG_TOP = R.id.tag_top_override;
     private static final int TAG_LAYOUT_TOP = R.id.tag_layout_top;
+    private static final int TAG_FIRST_LAYOUT = R.id.tag_is_first_layout;
     private static final int TAG_ALPHA_ANIMATOR = R.id.tag_alpha_animator;
     private static final ViewClippingUtil.ClippingParameters CLIPPING_PARAMETERS =
             view -> view.getId() == com.android.internal.R.id.notification_messaging;
-    private static final IntProperty<View> LOCAL_TRANSLATION_Y =
-            new IntProperty<View>("localTranslationY") {
+    private static final IntProperty<View> TOP =
+            new IntProperty<View>("top") {
                 @Override
                 public void setValue(View object, int value) {
-                    setLocalTranslationY(object, value);
+                    setTop(object, value);
                 }
 
                 @Override
                 public Integer get(View object) {
-                    return getLocalTranslationY(object);
+                    return getTop(object);
                 }
             };
 
     @Override
     public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft,
             int oldTop, int oldRight, int oldBottom) {
-        int oldHeight = oldBottom - oldTop;
-        Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
-        if (layoutTop != null) {
-            oldTop = layoutTop;
-        }
-        int topChange = oldTop - top;
-        if (oldHeight == 0 || topChange == 0 || !v.isShown() || isGone(v)) {
-            // First layout
+        setLayoutTop(v, top);
+        if (isFirstLayout(v)) {
+            setFirstLayout(v, false /* first */);
+            setTop(v, top);
             return;
         }
-        if (layoutTop != null) {
-            v.setTagInternal(TAG_LAYOUT_TOP, top);
-        }
-        int newHeight = bottom - top;
-        int heightDifference = oldHeight - newHeight;
-        // Only add the difference if the height changes and it's getting smaller
-        heightDifference = Math.max(heightDifference, 0);
-        startLocalTranslationFrom(v, topChange + heightDifference + getLocalTranslationY(v));
+        startTopAnimation(v, getTop(v), top, MessagingLayout.FAST_OUT_SLOW_IN);
     }
 
-    private boolean isGone(View view) {
-        if (view.getVisibility() == View.GONE) {
-            return true;
-        }
-        final ViewGroup.LayoutParams lp = view.getLayoutParams();
-        if (lp instanceof MessagingLinearLayout.LayoutParams
-                && ((MessagingLinearLayout.LayoutParams) lp).hide) {
-            return true;
-        }
-        return false;
-    }
-
-    public static void startLocalTranslationFrom(View v, int startTranslation) {
-        startLocalTranslationFrom(v, startTranslation, MessagingLayout.FAST_OUT_SLOW_IN);
-    }
-
-    public static void startLocalTranslationFrom(View v, int startTranslation,
-            Interpolator interpolator) {
-        startLocalTranslation(v, startTranslation, 0, interpolator);
-    }
-
-    public static void startLocalTranslationTo(View v, int endTranslation,
-            Interpolator interpolator) {
-        startLocalTranslation(v, getLocalTranslationY(v), endTranslation, interpolator);
-    }
-
-    public static int getLocalTranslationY(View v) {
-        Integer tag = (Integer) v.getTag(TAG_LOCAL_TRANSLATION_Y);
+    private static boolean isFirstLayout(View view) {
+        Boolean tag = (Boolean) view.getTag(TAG_FIRST_LAYOUT);
         if (tag == null) {
-            return 0;
+            return true;
         }
         return tag;
     }
 
-    private static void setLocalTranslationY(View v, int value) {
-        v.setTagInternal(TAG_LOCAL_TRANSLATION_Y, value);
+    public static void recycle(View view) {
+        setFirstLayout(view, true /* first */);
+    }
+
+    private static void setFirstLayout(View view, boolean first) {
+        view.setTagInternal(TAG_FIRST_LAYOUT, first);
+    }
+
+    private static void setLayoutTop(View view, int top) {
+        view.setTagInternal(TAG_LAYOUT_TOP, top);
+    }
+
+    public static int getLayoutTop(View view) {
+        Integer tag = (Integer) view.getTag(TAG_LAYOUT_TOP);
+        if (tag == null) {
+            return getTop(view);
+        }
+        return tag;
+    }
+
+    /**
+     * Start a translation animation from a start offset to the laid out location
+     * @param view The view to animate
+     * @param startTranslation The starting translation to start from.
+     * @param interpolator The interpolator to use.
+     */
+    public static void startLocalTranslationFrom(View view, int startTranslation,
+            Interpolator interpolator) {
+        startTopAnimation(view, getTop(view) + startTranslation, getLayoutTop(view), interpolator);
+    }
+
+    /**
+     * Start a translation animation from a start offset to the laid out location
+     * @param view The view to animate
+     * @param endTranslation The end translation to go to.
+     * @param interpolator The interpolator to use.
+     */
+    public static void startLocalTranslationTo(View view, int endTranslation,
+            Interpolator interpolator) {
+        int top = getTop(view);
+        startTopAnimation(view, top, top + endTranslation, interpolator);
+    }
+
+    public static int getTop(View v) {
+        Integer tag = (Integer) v.getTag(TAG_TOP);
+        if (tag == null) {
+            return v.getTop();
+        }
+        return tag;
+    }
+
+    private static void setTop(View v, int value) {
+        v.setTagInternal(TAG_TOP, value);
         updateTopAndBottom(v);
     }
 
     private static void updateTopAndBottom(View v) {
-        int layoutTop = (int) v.getTag(TAG_LAYOUT_TOP);
-        int localTranslation = getLocalTranslationY(v);
+        int top = getTop(v);
         int height = v.getHeight();
-        v.setTop(layoutTop + localTranslation);
-        v.setBottom(layoutTop + height + localTranslation);
+        v.setTop(top);
+        v.setBottom(height + top);
     }
 
-    private static void startLocalTranslation(final View v, int start, int end,
+    private static void startTopAnimation(final View v, int start, int end,
             Interpolator interpolator) {
-        ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR);
+        ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_TOP_ANIMATOR);
         if (existing != null) {
             existing.cancel();
         }
-        ObjectAnimator animator = ObjectAnimator.ofInt(v, LOCAL_TRANSLATION_Y, start, end);
-        Integer layoutTop = (Integer) v.getTag(TAG_LAYOUT_TOP);
-        if (layoutTop == null) {
-            layoutTop = v.getTop();
-            v.setTagInternal(TAG_LAYOUT_TOP, layoutTop);
+        if (!v.isShown() || start == end
+                || (MessagingLinearLayout.isGone(v) && !isHidingAnimated(v))) {
+            setTop(v, end);
+            return;
         }
-        setLocalTranslationY(v, start);
+        ObjectAnimator animator = ObjectAnimator.ofInt(v, TOP, start, end);
+        setTop(v, start);
         animator.setInterpolator(interpolator);
         animator.setDuration(APPEAR_ANIMATION_LENGTH);
         animator.addListener(new AnimatorListenerAdapter() {
@@ -143,12 +157,8 @@
 
             @Override
             public void onAnimationEnd(Animator animation) {
-                v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, null);
+                v.setTagInternal(TAG_TOP_ANIMATOR, null);
                 setClippingDeactivated(v, false);
-                if (!mCancelled) {
-                    setLocalTranslationY(v, 0);
-                    v.setTagInternal(TAG_LAYOUT_TOP, null);
-                }
             }
 
             @Override
@@ -157,10 +167,17 @@
             }
         });
         setClippingDeactivated(v, true);
-        v.setTagInternal(TAG_LOCAL_TRANSLATION_ANIMATOR, animator);
+        v.setTagInternal(TAG_TOP_ANIMATOR, animator);
         animator.start();
     }
 
+    private static boolean isHidingAnimated(View v) {
+        if (v instanceof MessagingLinearLayout.MessagingChild) {
+            return ((MessagingLinearLayout.MessagingChild) v).isHidingAnimated();
+        }
+        return false;
+    }
+
     public static void fadeIn(final View v) {
         ObjectAnimator existing = (ObjectAnimator) v.getTag(TAG_ALPHA_ANIMATOR);
         if (existing != null) {
@@ -199,6 +216,13 @@
         if (existing != null) {
             existing.cancel();
         }
+        if (!view.isShown() || (MessagingLinearLayout.isGone(view) && !isHidingAnimated(view))) {
+            view.setAlpha(0.0f);
+            if (endAction != null) {
+                endAction.run();
+            }
+            return;
+        }
         ObjectAnimator animator = ObjectAnimator.ofFloat(view, View.ALPHA,
                 view.getAlpha(), 0.0f);
         animator.setInterpolator(ALPHA_OUT);
@@ -224,10 +248,14 @@
     }
 
     public static boolean isAnimatingTranslation(View v) {
-        return v.getTag(TAG_LOCAL_TRANSLATION_ANIMATOR) != null;
+        return v.getTag(TAG_TOP_ANIMATOR) != null;
     }
 
     public static boolean isAnimatingAlpha(View v) {
         return v.getTag(TAG_ALPHA_ANIMATOR) != null;
     }
+
+    public static void setToLaidOutPosition(View view) {
+        setTop(view, getLayoutTop(view));
+    }
 }
diff --git a/core/java/com/android/internal/widget/MessagingTextMessage.java b/core/java/com/android/internal/widget/MessagingTextMessage.java
index 219116e..4081a86 100644
--- a/core/java/com/android/internal/widget/MessagingTextMessage.java
+++ b/core/java/com/android/internal/widget/MessagingTextMessage.java
@@ -92,8 +92,6 @@
 
     public void recycle() {
         MessagingMessage.super.recycle();
-        setAlpha(1.0f);
-        setTranslationY(0);
         sInstancePool.release(this);
     }
 
diff --git a/core/java/com/android/internal/widget/NotificationActionListLayout.java b/core/java/com/android/internal/widget/NotificationActionListLayout.java
index 9048f87..c7ea781 100644
--- a/core/java/com/android/internal/widget/NotificationActionListLayout.java
+++ b/core/java/com/android/internal/widget/NotificationActionListLayout.java
@@ -206,7 +206,17 @@
         final boolean centerAligned = (mGravity & Gravity.CENTER_HORIZONTAL) != 0;
 
         int childTop;
-        int childLeft = centerAligned ? left + (right - left) / 2 - mTotalWidth / 2 : 0;
+        int childLeft;
+        if (centerAligned) {
+            childLeft = mPaddingLeft + left + (right - left) / 2 - mTotalWidth / 2;
+        } else {
+            childLeft = mPaddingLeft;
+            int absoluteGravity = Gravity.getAbsoluteGravity(Gravity.START, getLayoutDirection());
+            if (absoluteGravity == Gravity.RIGHT) {
+                childLeft += right - left - mTotalWidth;
+            }
+        }
+
 
         // Where bottom of child should go
         final int height = bottom - top;
@@ -216,18 +226,6 @@
 
         final int count = getChildCount();
 
-        final int layoutDirection = getLayoutDirection();
-        switch (Gravity.getAbsoluteGravity(Gravity.START, layoutDirection)) {
-            case Gravity.RIGHT:
-                childLeft += mPaddingLeft + right - left - mTotalWidth;
-                break;
-
-            case Gravity.LEFT:
-            default:
-                childLeft += mPaddingLeft;
-                break;
-        }
-
         int start = 0;
         int dir = 1;
         //In case of RTL, start drawing from the last child.
diff --git a/core/jni/android/graphics/Bitmap.cpp b/core/jni/android/graphics/Bitmap.cpp
index 7352324..e5aea97 100755
--- a/core/jni/android/graphics/Bitmap.cpp
+++ b/core/jni/android/graphics/Bitmap.cpp
@@ -62,7 +62,7 @@
     }
 
     bool valid() {
-        return mBitmap;
+        return mBitmap != nullptr;
     }
 
     Bitmap& bitmap() {
@@ -851,10 +851,9 @@
     return static_cast<jlong>(reinterpret_cast<uintptr_t>(&Bitmap_destruct));
 }
 
-static jboolean Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
+static void Bitmap_recycle(JNIEnv* env, jobject, jlong bitmapHandle) {
     LocalScopedBitmap bitmap(bitmapHandle);
     bitmap->freePixels();
-    return JNI_TRUE;
 }
 
 static void Bitmap_reconfigure(JNIEnv* env, jobject clazz, jlong bitmapHandle,
@@ -1600,7 +1599,7 @@
     {   "nativeCopyAshmemConfig",   "(JI)Landroid/graphics/Bitmap;",
         (void*)Bitmap_copyAshmemConfig },
     {   "nativeGetNativeFinalizer", "()J", (void*)Bitmap_getNativeFinalizer },
-    {   "nativeRecycle",            "(J)Z", (void*)Bitmap_recycle },
+    {   "nativeRecycle",            "(J)V", (void*)Bitmap_recycle },
     {   "nativeReconfigure",        "(JIIIZ)V", (void*)Bitmap_reconfigure },
     {   "nativeCompress",           "(JIILjava/io/OutputStream;[B)Z",
         (void*)Bitmap_compress },
diff --git a/core/jni/android/graphics/FontFamily.cpp b/core/jni/android/graphics/FontFamily.cpp
index c7ad2a4..fb571df 100644
--- a/core/jni/android/graphics/FontFamily.cpp
+++ b/core/jni/android/graphics/FontFamily.cpp
@@ -44,9 +44,9 @@
 
 struct NativeFamilyBuilder {
     NativeFamilyBuilder(uint32_t langId, int variant)
-        : langId(langId), variant(static_cast<minikin::FontFamily::Variant>(variant)) {}
+        : langId(langId), variant(static_cast<minikin::FamilyVariant>(variant)) {}
     uint32_t langId;
-    minikin::FontFamily::Variant variant;
+    minikin::FamilyVariant variant;
     std::vector<minikin::Font> fonts;
     std::vector<minikin::FontVariation> axes;
 };
diff --git a/core/jni/android/graphics/Graphics.cpp b/core/jni/android/graphics/Graphics.cpp
index 0933e98..5d65aee 100644
--- a/core/jni/android/graphics/Graphics.cpp
+++ b/core/jni/android/graphics/Graphics.cpp
@@ -355,11 +355,6 @@
     bitmap::toBitmap(env, bitmap).getSkBitmap(outBitmap);
 }
 
-SkPixelRef* GraphicsJNI::refSkPixelRef(JNIEnv* env, jobject jbitmap) {
-    android::Bitmap& bitmap = android::bitmap::toBitmap(env, jbitmap);
-    bitmap.ref();
-    return &bitmap;
-}
 SkColorType GraphicsJNI::getNativeBitmapColorType(JNIEnv* env, jobject jconfig) {
     ALOG_ASSERT(env);
     if (NULL == jconfig) {
diff --git a/core/jni/android/graphics/GraphicsJNI.h b/core/jni/android/graphics/GraphicsJNI.h
index dcb81fa..7825f1d 100644
--- a/core/jni/android/graphics/GraphicsJNI.h
+++ b/core/jni/android/graphics/GraphicsJNI.h
@@ -63,7 +63,6 @@
 
     static android::Canvas* getNativeCanvas(JNIEnv*, jobject canvas);
     static void getSkBitmap(JNIEnv*, jobject bitmap, SkBitmap* outBitmap);
-    static SkPixelRef* refSkPixelRef(JNIEnv*, jobject bitmap);
     static SkRegion* getNativeRegion(JNIEnv*, jobject region);
 
     /*
diff --git a/core/jni/android/graphics/Paint.cpp b/core/jni/android/graphics/Paint.cpp
index e9c2e7a..d391de7 100644
--- a/core/jni/android/graphics/Paint.cpp
+++ b/core/jni/android/graphics/Paint.cpp
@@ -44,6 +44,7 @@
 #include <minikin/GraphemeBreak.h>
 #include <minikin/LocaleList.h>
 #include <minikin/Measurement.h>
+#include <minikin/MinikinPaint.h>
 #include <unicode/utf16.h>
 
 #include <cassert>
@@ -594,7 +595,7 @@
         // restore the original settings.
         paint->setTextSkewX(saveSkewX);
         paint->setFakeBoldText(savefakeBold);
-        if (paint->getFamilyVariant() == minikin::FontFamily::Variant::ELEGANT) {
+        if (paint->getFamilyVariant() == minikin::FamilyVariant::ELEGANT) {
             SkScalar size = paint->getTextSize();
             metrics->fTop = -size * kElegantTop / 2048;
             metrics->fBottom = -size * kElegantBottom / 2048;
@@ -893,13 +894,13 @@
 
     static jboolean isElegantTextHeight(jlong paintHandle) {
         Paint* obj = reinterpret_cast<Paint*>(paintHandle);
-        return obj->getFamilyVariant() == minikin::FontFamily::Variant::ELEGANT;
+        return obj->getFamilyVariant() == minikin::FamilyVariant::ELEGANT;
     }
 
     static void setElegantTextHeight(jlong paintHandle, jboolean aa) {
         Paint* obj = reinterpret_cast<Paint*>(paintHandle);
         obj->setFamilyVariant(
-                aa ? minikin::FontFamily::Variant::ELEGANT : minikin::FontFamily::Variant::DEFAULT);
+                aa ? minikin::FamilyVariant::ELEGANT : minikin::FamilyVariant::DEFAULT);
     }
 
     static jfloat getTextSize(jlong paintHandle) {
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/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index d7d8228..a72363c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -1294,11 +1294,8 @@
         handle = (audio_patch_handle_t)env->GetIntField(jPatchHandle, gAudioHandleFields.mId);
     }
 
-    struct audio_patch nPatch;
+    struct audio_patch nPatch = { .id = handle };
 
-    nPatch.id = handle;
-    nPatch.num_sources = 0;
-    nPatch.num_sinks = 0;
     jobject jSource = NULL;
     jobject jSink = NULL;
 
@@ -1584,7 +1581,7 @@
     if (!env->IsInstanceOf(jAudioPortConfig, gAudioPortConfigClass)) {
         return AUDIO_JAVA_BAD_VALUE;
     }
-    struct audio_port_config nAudioPortConfig;
+    struct audio_port_config nAudioPortConfig = {};
     jint jStatus = convertAudioPortConfigToNative(env, &nAudioPortConfig, jAudioPortConfig, true);
     if (jStatus != AUDIO_JAVA_SUCCESS) {
         return jStatus;
diff --git a/core/proto/android/server/activitymanagerservice.proto b/core/proto/android/server/activitymanagerservice.proto
index 418e15b..9d24588 100644
--- a/core/proto/android/server/activitymanagerservice.proto
+++ b/core/proto/android/server/activitymanagerservice.proto
@@ -117,6 +117,7 @@
     optional bool visible = 4;
     optional bool front_of_task = 5;
     optional int32 proc_id = 6;
+    optional bool translucent = 7;
 }
 
 message KeyguardControllerProto {
diff --git a/core/proto/android/server/forceappstandbytracker.proto b/core/proto/android/server/forceappstandbytracker.proto
index 1113d6a..8c71b0b 100644
--- a/core/proto/android/server/forceappstandbytracker.proto
+++ b/core/proto/android/server/forceappstandbytracker.proto
@@ -25,7 +25,7 @@
 
 // Dump from com.android.server.ForceAppStandbyTracker.
 //
-// Next ID: 12
+// Next ID: 13
 message ForceAppStandbyTrackerProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
@@ -41,6 +41,9 @@
     // App ids that are in power-save whitelist.
     repeated int32 power_save_whitelist_app_ids = 3;
 
+    // App ids that are in power-save user whitelist.
+    repeated int32 power_save_user_whitelist_app_ids = 12;
+
     // App ids that are in temporary power-save whitelist.
     repeated int32 temp_power_save_whitelist_app_ids = 4;
 
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index da206b7..1b41f99 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -850,7 +850,7 @@
 
     <!-- Used for permissions that are associated telephony features. -->
     <permission-group android:name="android.permission-group.CALL_LOG"
-        android:icon="@drawable/perm_group_phone_calls"
+        android:icon="@drawable/perm_group_call_log"
         android:label="@string/permgrouplab_calllog"
         android:description="@string/permgroupdesc_calllog"
         android:request="@string/permgrouprequest_calllog"
@@ -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
@@ -4287,21 +4296,6 @@
             </intent-filter>
         </receiver>
 
-        <receiver android:name="com.android.server.stats.StatsCompanionService$AnomalyAlarmReceiver"
-                  android:permission="android.permission.STATSCOMPANION"
-                  android:exported="false">
-        </receiver>
-
-        <receiver android:name="com.android.server.stats.StatsCompanionService$PullingAlarmReceiver"
-                  android:permission="android.permission.STATSCOMPANION"
-                  android:exported="false">
-        </receiver>
-
-        <receiver android:name="com.android.server.stats.StatsCompanionService$PeriodicAlarmReceiver"
-                  android:permission="android.permission.STATSCOMPANION"
-                  android:exported="false">
-        </receiver>
-
         <service android:name="android.hardware.location.GeofenceHardwareService"
             android:permission="android.permission.LOCATION_HARDWARE"
             android:exported="false" />
diff --git a/core/res/res/drawable/ic_arrow_forward.xml b/core/res/res/drawable/ic_arrow_forward.xml
new file mode 100644
index 0000000..f108570
--- /dev/null
+++ b/core/res/res/drawable/ic_arrow_forward.xml
@@ -0,0 +1,24 @@
+<!--
+    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.
+-->
+<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">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="M12.0,4.0l-1.41,1.41L16.17,11.0L4.0,11.0l0.0,2.0l12.17,0.0l-5.58,5.59L12.0,20.0l8.0,-8.0z"/>
+</vector>
diff --git a/core/res/res/drawable/ic_permission.xml b/core/res/res/drawable/ic_permission.xml
new file mode 100644
index 0000000..0052350
--- /dev/null
+++ b/core/res/res/drawable/ic_permission.xml
@@ -0,0 +1,26 @@
+<!--
+    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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="16.0"
+        android:viewportHeight="16.0">
+    <path
+        android:fillColor="#FF000000"
+        android:pathData="
+        M9.0,12l-2.0,0.0l0.0,-2.0l2.0,0.0l0.0,2.0z
+        m0.0,-4.0l-2.0,0.0l0.0,-4.0l2.0,0.0l0.0,4.0z"/>
+</vector>
diff --git a/core/res/res/drawable/perm_group_call_log.xml b/core/res/res/drawable/perm_group_call_log.xml
new file mode 100644
index 0000000..0dfdbee
--- /dev/null
+++ b/core/res/res/drawable/perm_group_call_log.xml
@@ -0,0 +1,29 @@
+<?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.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+        android:width="24dp"
+        android:height="24dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
+    <path
+        android:fillColor="#000000"
+        android:pathData="M16.01,14.48l-2.62,2.62c-2.75,-1.49 -5.01,-3.75 -6.5,-6.5l2.62,-2.62c0.24,-0.24 0.34,-0.58 0.27,-0.9L9.13,3.82c-0.09,-0.47 -0.5,-0.8 -0.98,-0.8L4,3.01c-0.56,0 -1.03,0.47 -1,1.03c0.17,2.91 1.04,5.63 2.43,8.01c1.57,2.69 3.81,4.93 6.5,6.5c2.38,1.39 5.1,2.26 8.01,2.43c0.56,0.03 1.03,-0.44 1.03,-1v-4.15c0,-0.48 -0.34,-0.89 -0.8,-0.98l-3.26,-0.65C16.58,14.14 16.24,14.24 16.01,14.48z"/>
+    <path
+        android:fillColor="#000000"
+        android:pathData="M12,8h10V6H12V8zM12,4h10V2H12V4zM22,10H12v2h10V10z"/>
+</vector>
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/core/res/res/values/config.xml b/core/res/res/values/config.xml
index b0ecb3e..c856ed8 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1108,6 +1108,15 @@
     <string-array translatable="false" name="config_ringtoneEffectUris">
     </string-array>
 
+    <!-- The default intensity level for haptic feedback. See
+         Settings.System.HAPTIC_FEEDBACK_INTENSITY more details on the constant values and
+         meanings. -->
+    <integer name="config_defaultHapticFeedbackIntensity">2</integer>
+    <!-- The default intensity level for notification vibrations. See
+         Settings.System.NOTIFICATION_VIBRATION_INTENSITY more details on the constant values and
+         meanings. -->
+    <integer name="config_defaultNotificationVibrationIntensity">2</integer>
+
     <bool name="config_use_strict_phone_number_comparation">false</bool>
 
     <!-- Display low battery warning when battery level dips to this value.
diff --git a/core/res/res/values/dimens.xml b/core/res/res/values/dimens.xml
index 2e8c7f9..471170b 100644
--- a/core/res/res/values/dimens.xml
+++ b/core/res/res/values/dimens.xml
@@ -55,7 +55,7 @@
     <!-- Width of the navigation bar when it is placed vertically on the screen in car mode -->
     <dimen name="navigation_bar_width_car_mode">96dp</dimen>
     <!-- Height of notification icons in the status bar -->
-    <dimen name="status_bar_icon_size">24dip</dimen>
+    <dimen name="status_bar_icon_size">22dip</dimen>
     <!-- Size of the giant number (unread count) in the notifications -->
     <dimen name="status_bar_content_number_size">48sp</dimen>
     <!-- Margin at the edge of the screen to ignore touch events for in the windowshade. -->
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 47d04ed..bf7e068 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -140,15 +140,18 @@
   <!-- Accessibility action identifier for {@link android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction#ACTION_MOVE_WINDOW}. -->
   <item type="id" name="accessibilityActionMoveWindow" />
 
-  <!-- A tag used to save an animator in local y translation -->
-  <item type="id" name="tag_local_translation_y_animator" />
+  <!-- A tag used to save an animator in top -->
+  <item type="id" name="tag_top_animator" />
 
-  <!-- A tag used to save the local translation y -->
-  <item type="id" name="tag_local_translation_y" />
+  <!-- A tag used to save the current top override -->
+  <item type="id" name="tag_top_override" />
 
   <!-- A tag used to save the original top of a view -->
   <item type="id" name="tag_layout_top" />
 
+  <!-- A tag used to save whether a view was laid out before -->
+  <item type="id" name="tag_is_first_layout" />
+
   <!-- A tag used to save an animator in alpha -->
   <item type="id" name="tag_alpha_animator" />
 
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 3c5159c..8f469b0 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -3362,7 +3362,7 @@
     <string name="locale_replacement">""</string>
 
     <!-- Title of the pop-up dialog in which the user switches keyboard, also known as input method. -->
-    <string name="select_input_method">Change keyboard</string>
+    <string name="select_input_method">Choose input method</string>
     <!-- Summary text of a toggle switch to enable/disable use of the IME while a physical
          keyboard is connected -->
     <string name="show_ime">Keep it on screen while physical keyboard is active</string>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 42aad6a..833228b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3260,9 +3260,10 @@
   <java-symbol type="id" name="message_name" />
   <java-symbol type="id" name="message_icon" />
   <java-symbol type="id" name="group_message_container" />
-  <java-symbol type="id" name="tag_local_translation_y_animator" />
-  <java-symbol type="id" name="tag_local_translation_y" />
+  <java-symbol type="id" name="tag_top_animator" />
+  <java-symbol type="id" name="tag_top_override" />
   <java-symbol type="id" name="tag_layout_top" />
+  <java-symbol type="id" name="tag_is_first_layout" />
   <java-symbol type="id" name="tag_alpha_animator" />
   <java-symbol type="id" name="clip_children_set_tag" />
   <java-symbol type="id" name="clip_to_padding_tag" />
@@ -3389,4 +3390,9 @@
   <java-symbol type="attr" name="opticalInsetBottom" />
 
   <java-symbol type="drawable" name="ic_lock_lockdown" />
+  <java-symbol type="drawable" name="ic_arrow_forward" />
+  <java-symbol type="drawable" name="ic_permission" />
+
+  <java-symbol type="integer" name="config_defaultHapticFeedbackIntensity" />
+  <java-symbol type="integer" name="config_defaultNotificationVibrationIntensity" />
 </resources>
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index c6ada7a..3d9e7d2 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -132,6 +132,7 @@
                     Settings.Global.BLE_SCAN_LOW_LATENCY_WINDOW_MS,
                     Settings.Global.BLE_SCAN_LOW_LATENCY_INTERVAL_MS,
                     Settings.Global.BLE_SCAN_BACKGROUND_MODE,
+                    Settings.Global.BLOCKED_SLICES,
                     Settings.Global.BLOCKING_HELPER_DISMISS_TO_VIEW_RATIO_LIMIT,
                     Settings.Global.BLOCKING_HELPER_STREAK_LIMIT,
                     Settings.Global.BLUETOOTH_A2DP_SINK_PRIORITY_PREFIX,
@@ -155,6 +156,7 @@
                     Settings.Global.CAPTIVE_PORTAL_HTTP_URL,
                     Settings.Global.CAPTIVE_PORTAL_MODE,
                     Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+                    Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS,
                     Settings.Global.CAPTIVE_PORTAL_SERVER,
                     Settings.Global.CAPTIVE_PORTAL_USE_HTTPS,
                     Settings.Global.CAPTIVE_PORTAL_USER_AGENT,
@@ -592,6 +594,7 @@
                  Settings.Secure.SHOW_ROTATION_SUGGESTIONS,
                  Settings.Secure.SKIP_FIRST_USE_HINTS, // candidate?
                  Settings.Secure.SMS_DEFAULT_APPLICATION,
+                 Settings.Secure.THEME_MODE,
                  Settings.Secure.TRUST_AGENTS_INITIALIZED,
                  Settings.Secure.TV_INPUT_CUSTOM_LABELS,
                  Settings.Secure.TV_INPUT_HIDDEN_INPUTS,
@@ -614,7 +617,9 @@
                  Settings.Secure.LOW_POWER_MANUAL_ACTIVATION_COUNT,
                  Settings.Secure.LOW_POWER_WARNING_ACKNOWLEDGED,
                  Settings.Secure.SUPPRESS_AUTO_BATTERY_SAVER_SUGGESTION,
-                 Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE);
+                 Settings.Secure.PACKAGES_TO_CLEAR_DATA_BEFORE_FULL_RESTORE,
+                 Settings.Secure.FLASHLIGHT_AVAILABLE,
+                 Settings.Secure.FLASHLIGHT_ENABLED);
 
     @Test
     public void systemSettingsBackedUpOrBlacklisted() {
diff --git a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
index 50f24d3..8909293 100644
--- a/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsValidatorsTest.java
@@ -88,6 +88,23 @@
     }
 
     @Test
+    public void testNullableComponentNameValidator_onValidComponentName_returnsTrue() {
+        assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(
+                "android/com.android.internal.backup.LocalTransport"));
+    }
+
+    @Test
+    public void testNullableComponentNameValidator_onInvalidComponentName_returnsFalse() {
+        assertFalse(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(
+                "rectangle"));
+    }
+
+    @Test
+    public void testNullableComponentNameValidator_onNullValue_returnsTrue() {
+        assertTrue(SettingsValidators.NULLABLE_COMPONENT_NAME_VALIDATOR.validate(null));
+    }
+
+    @Test
     public void testLocaleValidator() {
         assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("en_US"));
         assertTrue(SettingsValidators.LOCALE_VALIDATOR.validate("es"));
diff --git a/core/tests/coretests/src/android/text/LayoutTest.java b/core/tests/coretests/src/android/text/LayoutTest.java
index 5570bac..97937a4 100644
--- a/core/tests/coretests/src/android/text/LayoutTest.java
+++ b/core/tests/coretests/src/android/text/LayoutTest.java
@@ -711,6 +711,7 @@
             actual[i] = layout.primaryIsTrailingPrevious(i);
         }
         assertArrayEquals(expected, actual);
+        assertArrayEquals(actual, layout.primaryIsTrailingPreviousAllLineOffsets(0));
     }
 
     @Test
@@ -741,7 +742,6 @@
         assertPrimaryIsTrailingPrevious(
                 RTL + LRI + RTL + LTR + PDI + RTL,
                 new boolean[]{false, false, true, false, false, false, false});
-
     }
 }
 
diff --git a/core/tests/coretests/src/android/text/TextLineTest.java b/core/tests/coretests/src/android/text/TextLineTest.java
index b2fa2cf..d1e12fa 100644
--- a/core/tests/coretests/src/android/text/TextLineTest.java
+++ b/core/tests/coretests/src/android/text/TextLineTest.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
@@ -32,6 +33,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.Arrays;
+
 @Presubmit
 @SmallTest
 @RunWith(AndroidJUnit4.class)
@@ -90,8 +93,9 @@
             "fonts/StaticLayoutLineBreakingTestFont.ttf");
 
     private TextLine getTextLine(String str, TextPaint paint, TabStops tabStops) {
-        Layout layout = StaticLayout.Builder.obtain(str, 0, str.length(), paint, Integer.MAX_VALUE)
-                .build();
+        Layout layout =
+                StaticLayout.Builder.obtain(str, 0, str.length(), paint, Integer.MAX_VALUE)
+                    .build();
         TextLine tl = TextLine.obtain();
         tl.set(paint, str, 0, str.length(),
                 TextDirectionHeuristics.FIRSTSTRONG_LTR.isRtl(str, 0, str.length()) ? -1 : 1,
@@ -103,6 +107,18 @@
         return getTextLine(str, paint, null);
     }
 
+    private void assertMeasurements(final TextLine tl, final int length, boolean trailing,
+            final float[] expected) {
+        for (int offset = 0; offset <= length; ++offset) {
+            assertEquals(expected[offset], tl.measure(offset, trailing, null), 0.0f);
+        }
+
+        final boolean[] trailings = new boolean[length + 1];
+        Arrays.fill(trailings, trailing);
+        final float[] allMeasurements = tl.measureAllOffsets(trailings, null);
+        assertArrayEquals(expected, allMeasurements, 0.0f);
+    }
+
     @Test
     public void testMeasure_LTR() {
         final TextPaint paint = new TextPaint();
@@ -110,21 +126,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("IIIIIV", paint);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(20.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(30.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(40.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(50.0f, tl.measure(5, false, null), 0.0f);
-        assertEquals(100.0f, tl.measure(6, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(20.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(30.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(40.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(50.0f, tl.measure(5, true, null), 0.0f);
-        assertEquals(100.0f, tl.measure(6, true, null), 0.0f);
+        assertMeasurements(tl, 6, false,
+                new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f});
+        assertMeasurements(tl, 6, true,
+                new float[]{0.0f, 10.0f, 20.0f, 30.0f, 40.0f, 50.0f, 100.0f});
     }
 
     @Test
@@ -134,21 +139,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("\u05D0\u05D0\u05D0\u05D0\u05D0\u05D1", paint);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(-30.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(-40.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(-50.0f, tl.measure(5, false, null), 0.0f);
-        assertEquals(-100.0f, tl.measure(6, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(-30.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(-40.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(-50.0f, tl.measure(5, true, null), 0.0f);
-        assertEquals(-100.0f, tl.measure(6, true, null), 0.0f);
+        assertMeasurements(tl, 6, false,
+                new float[]{0.0f, -10.0f, -20.0f, -30.0f, -40.0f, -50.0f, -100.0f});
+        assertMeasurements(tl, 6, true,
+                new float[]{0.0f, -10.0f, -20.0f, -30.0f, -40.0f, -50.0f, -100.0f});
     }
 
     @Test
@@ -158,21 +152,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("II\u05D0\u05D0II", paint);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(40.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(30.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(40.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(50.0f, tl.measure(5, false, null), 0.0f);
-        assertEquals(60.0f, tl.measure(6, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(20.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(30.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(20.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(50.0f, tl.measure(5, true, null), 0.0f);
-        assertEquals(60.0f, tl.measure(6, true, null), 0.0f);
+        assertMeasurements(tl, 6, false,
+                new float[]{0.0f, 10.0f, 40.0f, 30.0f, 40.0f, 50.0f, 60.0f});
+        assertMeasurements(tl, 6, true,
+                new float[]{0.0f, 10.0f, 20.0f, 30.0f, 20.0f, 50.0f, 60.0f});
     }
 
     private static final String LRI = "\u2066";  // LEFT-TO-RIGHT ISOLATE
@@ -186,23 +169,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("I" + RLI + "I\u05D0\u05D0" + PDI + "I", paint);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(30.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(30.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(20.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(40.0f, tl.measure(5, false, null), 0.0f);
-        assertEquals(40.0f, tl.measure(6, false, null), 0.0f);
-        assertEquals(50.0f, tl.measure(7, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(40.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(20.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(5, true, null), 0.0f);
-        assertEquals(40.0f, tl.measure(6, true, null), 0.0f);
-        assertEquals(50.0f, tl.measure(7, true, null), 0.0f);
+        assertMeasurements(tl, 7, false,
+                new float[]{0.0f, 10.0f, 30.0f, 30.0f, 20.0f, 40.0f, 40.0f, 50.0f});
+        assertMeasurements(tl, 7, true,
+                new float[]{0.0f, 10.0f, 10.0f, 40.0f, 20.0f, 10.0f, 40.0f, 50.0f});
     }
 
     @Test
@@ -212,23 +182,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("\u05D0" + LRI + "\u05D0II" + PDI + "\u05D0", paint);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(-30.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(-30.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(-40.0f, tl.measure(5, false, null), 0.0f);
-        assertEquals(-40.0f, tl.measure(6, false, null), 0.0f);
-        assertEquals(-50.0f, tl.measure(7, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(-40.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(5, true, null), 0.0f);
-        assertEquals(-40.0f, tl.measure(6, true, null), 0.0f);
-        assertEquals(-50.0f, tl.measure(7, true, null), 0.0f);
+        assertMeasurements(tl, 7, false,
+                new float[]{0.0f, -10.0f, -30.0f, -30.0f, -20.0f, -40.0f, -40.0f, -50.0f});
+        assertMeasurements(tl, 7, true,
+                new float[]{0.0f, -10.0f, -10.0f, -40.0f, -20.0f, -10.0f, -40.0f, -50.0f});
     }
 
     @Test
@@ -240,17 +197,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("II\tII", paint, stops);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(20.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(100.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(110.0f, tl.measure(4, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(20.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(100.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(110.0f, tl.measure(4, true, null), 0.0f);
+        assertMeasurements(tl, 5, false,
+                new float[]{0.0f, 10.0f, 20.0f, 100.0f, 110.0f, 120.0f});
+        assertMeasurements(tl, 5, true,
+                new float[]{0.0f, 10.0f, 20.0f, 100.0f, 110.0f, 120.0f});
     }
 
     @Test
@@ -262,17 +212,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("\u05D0\u05D0\t\u05D0\u05D0", paint, stops);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(-100.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(-110.0f, tl.measure(4, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(-100.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(-110.0f, tl.measure(4, true, null), 0.0f);
+        assertMeasurements(tl, 5, false,
+                new float[]{0.0f, -10.0f, -20.0f, -100.0f, -110.0f, -120.0f});
+        assertMeasurements(tl, 5, true,
+                new float[]{0.0f, -10.0f, -20.0f, -100.0f, -110.0f, -120.0f});
     }
 
     @Test
@@ -284,19 +227,10 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("I\u05D0\tI\u05D0", paint, stops);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(20.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(20.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(100.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(120.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(120.0f, tl.measure(5, false, null), 0.0f);
-
-        assertEquals(0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(10.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(100.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(110.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(110.0f, tl.measure(5, true, null), 0.0f);
+        assertMeasurements(tl, 5, false,
+                new float[]{0.0f, 20.0f, 20.0f, 100.0f, 120.0f, 120.0f});
+        assertMeasurements(tl, 5, true,
+                new float[]{0.0f, 10.0f, 10.0f, 100.0f, 110.0f, 110.0f});
     }
 
     @Test
@@ -308,18 +242,9 @@
         paint.setTextSize(10.0f);  // make 1em = 10px
 
         TextLine tl = getTextLine("\u05D0I\t\u05D0I", paint, stops);
-        assertEquals(0.0f, tl.measure(0, false, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(1, false, null), 0.0f);
-        assertEquals(-20.0f, tl.measure(2, false, null), 0.0f);
-        assertEquals(-100.0f, tl.measure(3, false, null), 0.0f);
-        assertEquals(-120.0f, tl.measure(4, false, null), 0.0f);
-        assertEquals(-120.0f, tl.measure(5, false, null), 0.0f);
-
-        assertEquals(-0.0f, tl.measure(0, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(1, true, null), 0.0f);
-        assertEquals(-10.0f, tl.measure(2, true, null), 0.0f);
-        assertEquals(-100.0f, tl.measure(3, true, null), 0.0f);
-        assertEquals(-110.0f, tl.measure(4, true, null), 0.0f);
-        assertEquals(-110.0f, tl.measure(5, true, null), 0.0f);
+        assertMeasurements(tl, 5, false,
+                new float[]{0.0f, -20.0f, -20.0f, -100.0f, -120.0f, -120.0f});
+        assertMeasurements(tl, 5, true,
+                new float[]{0.0f, -10.0f, -10.0f, -100.0f, -110.0f, -110.0f});
     }
 }
diff --git a/core/tests/coretests/src/android/view/ViewRootImplTest.java b/core/tests/coretests/src/android/view/ViewRootImplTest.java
new file mode 100644
index 0000000..c8e46fc
--- /dev/null
+++ b/core/tests/coretests/src/android/view/ViewRootImplTest.java
@@ -0,0 +1,143 @@
+/*
+ * 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.
+ */
+
+package android.view;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.junit.Assert.assertThat;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.platform.test.annotations.Presubmit;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+
+@Presubmit
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class ViewRootImplTest {
+
+    private Context mContext;
+    private ViewRootImplAccessor mViewRootImpl;
+
+    @Before
+    public void setUp() throws Exception {
+        mContext = InstrumentationRegistry.getContext();
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mViewRootImpl = new ViewRootImplAccessor(
+                    new ViewRootImpl(mContext, mContext.getDisplay()));
+        });
+    }
+
+    @Test
+    public void negativeInsets_areSetToZero() throws Exception {
+        mViewRootImpl.getAttachInfo().getContentInsets().set(-10, -20, -30 , -40);
+        mViewRootImpl.getAttachInfo().getStableInsets().set(-10, -20, -30 , -40);
+        final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
+
+        assertThat(insets.getSystemWindowInsets(), equalTo(new Rect()));
+        assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                insets.getStableInsetRight(), insets.getStableInsetBottom()), equalTo(new Rect()));
+    }
+
+    @Test
+    public void negativeInsets_areSetToZero_positiveAreLeftAsIs() throws Exception {
+        mViewRootImpl.getAttachInfo().getContentInsets().set(-10, 20, -30 , 40);
+        mViewRootImpl.getAttachInfo().getStableInsets().set(10, -20, 30 , -40);
+        final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
+
+        assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(0, 20, 0, 40)));
+        assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                insets.getStableInsetRight(), insets.getStableInsetBottom()),
+                equalTo(new Rect(10, 0, 30, 0)));
+    }
+
+    @Test
+    public void positiveInsets_areLeftAsIs() throws Exception {
+        mViewRootImpl.getAttachInfo().getContentInsets().set(10, 20, 30 , 40);
+        mViewRootImpl.getAttachInfo().getStableInsets().set(10, 20, 30 , 40);
+        final WindowInsets insets = mViewRootImpl.getWindowInsets(true /* forceConstruct */);
+
+        assertThat(insets.getSystemWindowInsets(), equalTo(new Rect(10, 20, 30, 40)));
+        assertThat(new Rect(insets.getStableInsetLeft(), insets.getStableInsetTop(),
+                insets.getStableInsetRight(), insets.getStableInsetBottom()),
+                equalTo(new Rect(10, 20, 30, 40)));
+    }
+
+    private static class ViewRootImplAccessor {
+
+        private final ViewRootImpl mViewRootImpl;
+
+        ViewRootImplAccessor(ViewRootImpl viewRootImpl) {
+            mViewRootImpl = viewRootImpl;
+        }
+
+        public ViewRootImpl get() {
+            return mViewRootImpl;
+        }
+
+        AttachInfoAccessor getAttachInfo() throws Exception {
+            return new AttachInfoAccessor(
+                    getField(mViewRootImpl, ViewRootImpl.class.getDeclaredField("mAttachInfo")));
+        }
+
+        WindowInsets getWindowInsets(boolean forceConstruct) throws Exception {
+            return (WindowInsets) invokeMethod(mViewRootImpl,
+                    ViewRootImpl.class.getDeclaredMethod("getWindowInsets", boolean.class),
+                    forceConstruct);
+        }
+
+        class AttachInfoAccessor {
+
+            private final Class<?> mClass;
+            private final Object mAttachInfo;
+
+            AttachInfoAccessor(Object attachInfo) throws Exception {
+                mAttachInfo = attachInfo;
+                mClass = ViewRootImpl.class.getClassLoader().loadClass(
+                        "android.view.View$AttachInfo");
+            }
+
+            Rect getContentInsets() throws Exception {
+                return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mContentInsets"));
+            }
+
+            Rect getStableInsets() throws Exception {
+                return (Rect) getField(mAttachInfo, mClass.getDeclaredField("mStableInsets"));
+            }
+        }
+
+        private static Object getField(Object o, Field field) throws Exception {
+            field.setAccessible(true);
+            return field.get(o);
+        }
+
+        private static Object invokeMethod(Object o, Method method, Object... args)
+                throws Exception {
+            method.setAccessible(true);
+            return method.invoke(o, args);
+        }
+    }
+}
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index a6cbd49..df84a4c 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -186,8 +186,6 @@
             file="/system/framework/android.test.mock.jar" />
     <library name="android.test.runner"
             file="/system/framework/android.test.runner.jar" />
-    <library name="javax.obex"
-            file="/system/framework/javax.obex.jar" />
 
     <!-- These are the standard packages that are white-listed to always have internet
          access while in power save mode, even if they aren't in the foreground. -->
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java
index d6c119f..0ff958f 100644
--- a/graphics/java/android/graphics/Bitmap.java
+++ b/graphics/java/android/graphics/Bitmap.java
@@ -344,14 +344,9 @@
      * there are no more references to this bitmap.
      */
     public void recycle() {
-        if (!mRecycled && mNativePtr != 0) {
-            if (nativeRecycle(mNativePtr)) {
-                // return value indicates whether native pixel object was actually recycled.
-                // false indicates that it is still in use at the native level and these
-                // objects should not be collected now. They will be collected later when the
-                // Bitmap itself is collected.
-                mNinePatchChunk = null;
-            }
+        if (!mRecycled) {
+            nativeRecycle(mNativePtr);
+            mNinePatchChunk = null;
             mRecycled = true;
         }
     }
@@ -2052,7 +2047,7 @@
     private static native Bitmap nativeCopyAshmem(long nativeSrcBitmap);
     private static native Bitmap nativeCopyAshmemConfig(long nativeSrcBitmap, int nativeConfig);
     private static native long nativeGetNativeFinalizer();
-    private static native boolean nativeRecycle(long nativeBitmap);
+    private static native void nativeRecycle(long nativeBitmap);
     private static native void nativeReconfigure(long nativeBitmap, int width, int height,
                                                  int config, boolean isPremultiplied);
 
diff --git a/libs/androidfw/ResourceTypes.cpp b/libs/androidfw/ResourceTypes.cpp
index 007cddd..b644cc3 100644
--- a/libs/androidfw/ResourceTypes.cpp
+++ b/libs/androidfw/ResourceTypes.cpp
@@ -458,7 +458,7 @@
 
     // The chunk must be at least the size of the string pool header.
     if (size < sizeof(ResStringPool_header)) {
-        LOG_ALWAYS_FATAL("Bad string block: data size %zu is too small to be a string block", size);
+        ALOGW("Bad string block: data size %zu is too small to be a string block", size);
         return (mError=BAD_TYPE);
     }
 
@@ -468,7 +468,7 @@
     if (validate_chunk(reinterpret_cast<const ResChunk_header*>(data), sizeof(ResStringPool_header),
                        reinterpret_cast<const uint8_t*>(data) + size,
                        "ResStringPool_header") != NO_ERROR) {
-        LOG_ALWAYS_FATAL("Bad string block: malformed block dimensions");
+        ALOGW("Bad string block: malformed block dimensions");
         return (mError=BAD_TYPE);
     }
 
diff --git a/libs/hwui/hwui/MinikinSkia.cpp b/libs/hwui/hwui/MinikinSkia.cpp
index a52263c..0022c93 100644
--- a/libs/hwui/hwui/MinikinSkia.cpp
+++ b/libs/hwui/hwui/MinikinSkia.cpp
@@ -22,6 +22,11 @@
 #include <SkTypeface.h>
 #include <log/log.h>
 
+#include <minikin/Font.h>
+#include <minikin/MinikinExtent.h>
+#include <minikin/MinikinPaint.h>
+#include <minikin/MinikinRect.h>
+
 namespace android {
 
 MinikinFontSkia::MinikinFontSkia(sk_sp<SkTypeface> typeface, const void* fontData, size_t fontSize,
diff --git a/libs/hwui/hwui/Paint.h b/libs/hwui/hwui/Paint.h
index 002f759..31d3c0d 100644
--- a/libs/hwui/hwui/Paint.h
+++ b/libs/hwui/hwui/Paint.h
@@ -25,6 +25,7 @@
 #include <string>
 
 #include <minikin/FontFamily.h>
+#include <minikin/FamilyVariant.h>
 
 namespace android {
 
@@ -73,9 +74,9 @@
 
     uint32_t getMinikinLocaleListId() const { return mMinikinLocaleListId; }
 
-    void setFamilyVariant(minikin::FontFamily::Variant variant) { mFamilyVariant = variant; }
+    void setFamilyVariant(minikin::FamilyVariant variant) { mFamilyVariant = variant; }
 
-    minikin::FontFamily::Variant getFamilyVariant() const { return mFamilyVariant; }
+    minikin::FamilyVariant getFamilyVariant() const { return mFamilyVariant; }
 
     void setHyphenEdit(uint32_t hyphen) { mHyphenEdit = hyphen; }
 
@@ -90,7 +91,7 @@
     float mWordSpacing = 0;
     std::string mFontFeatureSettings;
     uint32_t mMinikinLocaleListId;
-    minikin::FontFamily::Variant mFamilyVariant;
+    minikin::FamilyVariant mFamilyVariant;
     uint32_t mHyphenEdit = 0;
     // The native Typeface object has the same lifetime of the Java Typeface
     // object. The Java Paint object holds a strong reference to the Java Typeface
diff --git a/libs/hwui/hwui/PaintImpl.cpp b/libs/hwui/hwui/PaintImpl.cpp
index ae9c475..29cc890 100644
--- a/libs/hwui/hwui/PaintImpl.cpp
+++ b/libs/hwui/hwui/PaintImpl.cpp
@@ -24,7 +24,7 @@
         , mWordSpacing(0)
         , mFontFeatureSettings()
         , mMinikinLocaleListId(0)
-        , mFamilyVariant(minikin::FontFamily::Variant::DEFAULT) {}
+        , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {}
 
 Paint::Paint(const Paint& paint)
         : SkPaint(paint)
@@ -42,7 +42,7 @@
         , mWordSpacing(0)
         , mFontFeatureSettings()
         , mMinikinLocaleListId(0)
-        , mFamilyVariant(minikin::FontFamily::Variant::DEFAULT) {}
+        , mFamilyVariant(minikin::FamilyVariant::DEFAULT) {}
 
 Paint::~Paint() {}
 
diff --git a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
index 7b69b63..08f8da8 100644
--- a/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/GLFunctorDrawable.cpp
@@ -77,13 +77,20 @@
     // apply a simple clip with a scissor or a complex clip with a stencil
     SkRegion clipRegion;
     canvas->temporary_internal_getRgnClip(&clipRegion);
+    canvas->flush();
+    glBindFramebuffer(GL_FRAMEBUFFER, 0);
+    glViewport(0, 0, info.width, info.height);
     if (CC_UNLIKELY(clipRegion.isComplex())) {
+        //TODO: move stencil clear and canvas flush to SkAndroidFrameworkUtils::clipWithStencil
         glDisable(GL_SCISSOR_TEST);
         glStencilMask(0x1);
         glClearStencil(0);
         glClear(GL_STENCIL_BUFFER_BIT);
+        // GL ops get inserted here if previous flush is missing, which could dirty the stencil
         bool stencilWritten = SkAndroidFrameworkUtils::clipWithStencil(canvas);
-        canvas->flush();
+        canvas->flush(); //need this flush for the single op that draws into the stencil
+        glBindFramebuffer(GL_FRAMEBUFFER, 0);
+        glViewport(0, 0, info.width, info.height);
         if (stencilWritten) {
             glStencilMask(0x1);
             glStencilFunc(GL_EQUAL, 0x1, 0x1);
@@ -94,11 +101,9 @@
             glDisable(GL_STENCIL_TEST);
         }
     } else if (clipRegion.isEmpty()) {
-        canvas->flush();
         glDisable(GL_STENCIL_TEST);
         glDisable(GL_SCISSOR_TEST);
     } else {
-        canvas->flush();
         glDisable(GL_STENCIL_TEST);
         glEnable(GL_SCISSOR_TEST);
         setScissor(info.height, clipRegion.getBounds());
diff --git a/libs/hwui/pipeline/skia/LayerDrawable.cpp b/libs/hwui/pipeline/skia/LayerDrawable.cpp
index 00ba7130..14d31b2 100644
--- a/libs/hwui/pipeline/skia/LayerDrawable.cpp
+++ b/libs/hwui/pipeline/skia/LayerDrawable.cpp
@@ -114,7 +114,7 @@
         }
     }
 
-    return layerImage;
+    return layerImage != nullptr;
 }
 
 };  // namespace skiapipeline
diff --git a/location/java/android/location/Location.java b/location/java/android/location/Location.java
index 703f2dc..684cafa 100644
--- a/location/java/android/location/Location.java
+++ b/location/java/android/location/Location.java
@@ -1033,6 +1033,9 @@
     /**
      * Sets the extra information associated with this fix to the
      * given Bundle.
+     *
+     * <p>Note this stores a copy of the given extras, so any changes to extras after calling this
+     * method won't be reflected in the location bundle.
      */
     public void setExtras(Bundle extras) {
         mExtras = (extras == null) ? null : new Bundle(extras);
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index f210eea..196b886 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3940,6 +3940,7 @@
      * @param device Bluetooth device connected/disconnected
      * @param state  new connection state (BluetoothProfile.STATE_xxx)
      * @param profile profile for the A2DP device
+     * @param a2dpVolume New volume for the connecting device. Does nothing if disconnecting.
      * (either {@link android.bluetooth.BluetoothProfile.A2DP} or
      * {@link android.bluetooth.BluetoothProfile.A2DP_SINK})
      * @param suppressNoisyIntent if true the
@@ -3949,12 +3950,13 @@
      * {@hide}
      */
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent) {
+                BluetoothDevice device, int state, int profile,
+                boolean suppressNoisyIntent, int a2dpVolume) {
         final IAudioService service = getService();
         int delay = 0;
         try {
             delay = service.setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(device,
-                state, profile, suppressNoisyIntent);
+                state, profile, suppressNoisyIntent, a2dpVolume);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
@@ -4718,7 +4720,7 @@
                 NativeEventHandlerDelegate delegate =
                         new NativeEventHandlerDelegate(callback, handler);
                 mDeviceCallbacks.put(callback, delegate);
-                broadcastDeviceListChange(delegate.getHandler());
+                broadcastDeviceListChange_sync(delegate.getHandler());
             }
         }
     }
@@ -4837,9 +4839,9 @@
 
     /**
      * Internal method to compute and generate add/remove messages and then send to any
-     * registered callbacks.
+     * registered callbacks. Must be called synchronized on mDeviceCallbacks.
      */
-    private void broadcastDeviceListChange(Handler handler) {
+    private void broadcastDeviceListChange_sync(Handler handler) {
         int status;
 
         // Get the new current set of ports
@@ -4861,20 +4863,18 @@
             AudioDeviceInfo[] removed_devices =
                     calcListDeltas(current_ports, mPreviousPorts, GET_DEVICES_ALL);
             if (added_devices.length != 0 || removed_devices.length != 0) {
-                synchronized (mDeviceCallbacks) {
-                    for (int i = 0; i < mDeviceCallbacks.size(); i++) {
-                        handler = mDeviceCallbacks.valueAt(i).getHandler();
-                        if (handler != null) {
-                            if (removed_devices.length != 0) {
-                                handler.sendMessage(Message.obtain(handler,
-                                                                   MSG_DEVICES_DEVICES_REMOVED,
-                                                                   removed_devices));
-                            }
-                            if (added_devices.length != 0) {
-                                handler.sendMessage(Message.obtain(handler,
-                                                                   MSG_DEVICES_DEVICES_ADDED,
-                                                                   added_devices));
-                            }
+                for (int i = 0; i < mDeviceCallbacks.size(); i++) {
+                    handler = mDeviceCallbacks.valueAt(i).getHandler();
+                    if (handler != null) {
+                        if (removed_devices.length != 0) {
+                            handler.sendMessage(Message.obtain(handler,
+                                    MSG_DEVICES_DEVICES_REMOVED,
+                                    removed_devices));
+                        }
+                        if (added_devices.length != 0) {
+                            handler.sendMessage(Message.obtain(handler,
+                                    MSG_DEVICES_DEVICES_ADDED,
+                                    added_devices));
                         }
                     }
                 }
@@ -4890,7 +4890,9 @@
     private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
         static final String TAG = "OnAmPortUpdateListener";
         public void onAudioPortListUpdate(AudioPort[] portList) {
-            broadcastDeviceListChange(null);
+            synchronized (mDeviceCallbacks) {
+                broadcastDeviceListChange_sync(null);
+            }
         }
 
         /**
@@ -4904,7 +4906,9 @@
          * Callback method called when the mediaserver dies
          */
         public void onServiceDied() {
-            broadcastDeviceListChange(null);
+            synchronized (mDeviceCallbacks) {
+                broadcastDeviceListChange_sync(null);
+            }
         }
     }
 
diff --git a/media/java/android/media/IAudioService.aidl b/media/java/android/media/IAudioService.aidl
index 4af8850..569db16 100644
--- a/media/java/android/media/IAudioService.aidl
+++ b/media/java/android/media/IAudioService.aidl
@@ -211,7 +211,7 @@
     oneway void playerHasOpPlayAudio(in int piid, in boolean hasOpPlayAudio);
 
     int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(in BluetoothDevice device,
-            int state, int profile, boolean suppressNoisyIntent);
+            int state, int profile, boolean suppressNoisyIntent, int a2dpVolume);
 
     oneway void setFocusRequestResultFromExtPolicy(in AudioFocusInfo afi, int requestResult,
             in IAudioPolicyCallback pcb);
diff --git a/media/java/android/media/Image.java b/media/java/android/media/Image.java
index 9828275..a768dd3 100644
--- a/media/java/android/media/Image.java
+++ b/media/java/android/media/Image.java
@@ -207,8 +207,9 @@
      * after  {@link Image#close Image.close()} has been called.
      * </p>
      * @return the HardwareBuffer associated with this Image or null if this Image doesn't support
-     * this feature (e.g. {@link android.media.ImageWriter ImageWriter} or
-     * {@link android.media.MediaCodec MediaCodec} don't).
+     * this feature. (Unsupported use cases include Image instances obtained through
+     * {@link android.media.MediaCodec MediaCodec}, and on versions prior to Android P,
+     * {@link android.media.ImageWriter ImageWriter}).
      */
     @Nullable
     public HardwareBuffer getHardwareBuffer() {
diff --git a/media/java/android/media/ImageWriter.java b/media/java/android/media/ImageWriter.java
index 397768a..4c0153f 100644
--- a/media/java/android/media/ImageWriter.java
+++ b/media/java/android/media/ImageWriter.java
@@ -20,6 +20,7 @@
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.hardware.camera2.utils.SurfaceUtils;
+import android.hardware.HardwareBuffer;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.Message;
@@ -58,12 +59,17 @@
  * </p>
  * <p>
  * If the application already has an Image from {@link ImageReader}, the
- * application can directly queue this Image into ImageWriter (via
- * {@link #queueInputImage}), potentially with zero buffer copies. For the
- * {@link ImageFormat#PRIVATE PRIVATE} format Images produced by
- * {@link ImageReader}, this is the only way to send Image data to ImageWriter,
- * as the Image data aren't accessible by the application.
+ * application can directly queue this Image into the ImageWriter (via
+ * {@link #queueInputImage}), potentially with zero buffer copies. This
+ * even works if the image format of the ImageWriter is
+ * {@link ImageFormat#PRIVATE PRIVATE}, and prior to Android P is the only
+ * way to enqueue images into such an ImageWriter. Starting in Android P
+ * private images may also be accessed through their hardware buffers
+ * (when available) through the {@link Image#getHardwareBuffer()} method.
+ * Attempting to access the planes of a private image, will return an
+ * empty array.
  * </p>
+ * <p>
  * Once new input Images are queued into an ImageWriter, it's up to the
  * downstream components (e.g. {@link ImageReader} or
  * {@link android.hardware.camera2.CameraDevice}) to consume the Images. If the
@@ -257,29 +263,26 @@
      * <p>
      * If the format of ImageWriter is {@link ImageFormat#PRIVATE PRIVATE} (
      * {@link ImageWriter#getFormat()} == {@link ImageFormat#PRIVATE}), the
-     * image buffer is inaccessible to the application, and calling this method
-     * will result in an {@link IllegalStateException}. Instead, the application
-     * should acquire images from some other component (e.g. an
+     * image buffer is accessible to the application only through the hardware
+     * buffer obtained through {@link Image#getHardwareBuffer()}. (On Android
+     * versions prior to P, dequeueing private buffers will cause an
+     * {@link IllegalStateException} to be thrown). Alternatively,
+     * the application can acquire images from some other component (e.g. an
      * {@link ImageReader}), and queue them directly to this ImageWriter via the
      * {@link ImageWriter#queueInputImage queueInputImage()} method.
      * </p>
      *
      * @return The next available input Image from this ImageWriter.
      * @throws IllegalStateException if {@code maxImages} Images are currently
-     *             dequeued, or the ImageWriter format is
-     *             {@link ImageFormat#PRIVATE PRIVATE}, or the input
-     *             {@link android.view.Surface Surface} has been abandoned by the
-     *             consumer component that provided the {@link android.view.Surface Surface}.
+     *             dequeued, or the input {@link android.view.Surface Surface}
+     *             has been abandoned by the consumer component that provided
+     *             the {@link android.view.Surface Surface}. Prior to Android
+     *             P, throws if the ImageWriter format is
+     *             {@link ImageFormat#PRIVATE PRIVATE}.
      * @see #queueInputImage
      * @see Image#close
      */
     public Image dequeueInputImage() {
-        if (mWriterFormat == ImageFormat.PRIVATE) {
-            throw new IllegalStateException(
-                    "PRIVATE format ImageWriter doesn't support this operation since the images are"
-                            + " inaccessible to the application!");
-        }
-
         if (mDequeuedImages.size() >= mMaxImages) {
             throw new IllegalStateException("Already dequeued max number of Images " + mMaxImages);
         }
@@ -743,6 +746,13 @@
         }
 
         @Override
+        public HardwareBuffer getHardwareBuffer() {
+            throwISEIfImageIsInvalid();
+
+            return nativeGetHardwareBuffer();
+        }
+
+        @Override
         public Plane[] getPlanes() {
             throwISEIfImageIsInvalid();
 
@@ -863,6 +873,8 @@
         private synchronized native int nativeGetHeight();
 
         private synchronized native int nativeGetFormat();
+
+        private synchronized native HardwareBuffer nativeGetHardwareBuffer();
     }
 
     // Native implemented ImageWriter methods.
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 392a1eb..ada91be 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -2848,8 +2848,12 @@
                     mInbandTrackIndices.set(i);
                 }
 
+                if (tracks[i] == null) {
+                    Log.w(TAG, "unexpected NULL track at index " + i);
+                }
                 // newly appeared inband track
-                if (tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
+                if (tracks[i] != null
+                        && tracks[i].getTrackType() == TrackInfo.MEDIA_TRACK_TYPE_SUBTITLE) {
                     SubtitleTrack track = mSubtitleController.addTrack(
                             tracks[i].getFormat());
                     mIndexTrackPairs.add(Pair.create(i, track));
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index fefa1ed..0dddaf5 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -952,7 +952,8 @@
 
         // Find a filename. Throws FileNotFoundException if none can be found.
         final File outFile = Utils.getUniqueExternalFile(mContext, subdirectory,
-                Utils.getFileDisplayNameFromUri(mContext, fileUri), mimeType);
+                FileUtils.buildValidFatFilename(Utils.getFileDisplayNameFromUri(mContext, fileUri)),
+                        mimeType);
 
         // Copy contents to external ringtone storage. Throws IOException if the copy fails.
         try (final InputStream input = mContext.getContentResolver().openInputStream(fileUri);
diff --git a/media/java/android/media/audiofx/DynamicsProcessing.java b/media/java/android/media/audiofx/DynamicsProcessing.java
index 4c17ae1..1c3cff9 100644
--- a/media/java/android/media/audiofx/DynamicsProcessing.java
+++ b/media/java/android/media/audiofx/DynamicsProcessing.java
@@ -279,25 +279,24 @@
     private static final boolean PREEQ_DEFAULT_ENABLED = true;
     private static final boolean POSTEQ_DEFAULT_ENABLED = true;
 
-
     private static final boolean MBC_DEFAULT_ENABLED = true;
-    private static final float MBC_DEFAULT_ATTACK_TIME = 50; // ms
-    private static final float MBC_DEFAULT_RELEASE_TIME = 120; // ms
-    private static final float MBC_DEFAULT_RATIO = 2; // 1:N
-    private static final float MBC_DEFAULT_THRESHOLD = -30; // dB
+    private static final float MBC_DEFAULT_ATTACK_TIME = 3; // ms
+    private static final float MBC_DEFAULT_RELEASE_TIME = 80; // ms
+    private static final float MBC_DEFAULT_RATIO = 1; // N:1
+    private static final float MBC_DEFAULT_THRESHOLD = -45; // dB
     private static final float MBC_DEFAULT_KNEE_WIDTH = 0; // dB
-    private static final float MBC_DEFAULT_NOISE_GATE_THRESHOLD = -80; // dB
-    private static final float MBC_DEFAULT_EXPANDER_RATIO = 1.5f; // N:1
+    private static final float MBC_DEFAULT_NOISE_GATE_THRESHOLD = -90; // dB
+    private static final float MBC_DEFAULT_EXPANDER_RATIO = 1; // 1:N
     private static final float MBC_DEFAULT_PRE_GAIN = 0; // dB
-    private static final float MBC_DEFAULT_POST_GAIN = 10; // dB
+    private static final float MBC_DEFAULT_POST_GAIN = 0; // dB
 
     private static final boolean LIMITER_DEFAULT_ENABLED = true;
     private static final int LIMITER_DEFAULT_LINK_GROUP = 0;//;
-    private static final float LIMITER_DEFAULT_ATTACK_TIME = 50; // ms
-    private static final float LIMITER_DEFAULT_RELEASE_TIME = 120; // ms
-    private static final float LIMITER_DEFAULT_RATIO = 2; // 1:N
-    private static final float LIMITER_DEFAULT_THRESHOLD = -30; // dB
-    private static final float LIMITER_DEFAULT_POST_GAIN = 10; // dB
+    private static final float LIMITER_DEFAULT_ATTACK_TIME = 1; // ms
+    private static final float LIMITER_DEFAULT_RELEASE_TIME = 60; // ms
+    private static final float LIMITER_DEFAULT_RATIO = 10; // N:1
+    private static final float LIMITER_DEFAULT_THRESHOLD = -2; // dB
+    private static final float LIMITER_DEFAULT_POST_GAIN = 0; // dB
 
     private static final float DEFAULT_MIN_FREQUENCY = 220; // Hz
     private static final float DEFAULT_MAX_FREQUENCY = 20000; // Hz
@@ -540,13 +539,14 @@
          * band number, thus band 0 cutoffFrequency <= band 1 cutoffFrequency, and so on.
          * @param attackTime Attack Time for compressor in milliseconds (ms)
          * @param releaseTime Release Time for compressor in milliseconds (ms)
-         * @param ratio Compressor ratio (1:N)
+         * @param ratio Compressor ratio (N:1) (input:output)
          * @param threshold Compressor threshold measured in decibels (dB) from 0 dB Full Scale
          * (dBFS).
          * @param kneeWidth Width in decibels (dB) around compressor threshold point.
          * @param noiseGateThreshold Noise gate threshold in decibels (dB) from 0 dB Full Scale
          * (dBFS).
-         * @param expanderRatio Expander ratio (N:1) for signals below the Noise Gate Threshold.
+         * @param expanderRatio Expander ratio (1:N) (input:output) for signals below the Noise Gate
+         * Threshold.
          * @param preGain Gain applied to the signal BEFORE the compression.
          * @param postGain Gain applied to the signal AFTER compression.
          */
@@ -618,13 +618,13 @@
          */
         public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; }
         /**
-         * gets the compressor ratio (1:N)
-         * @return compressor ratio (1:N)
+         * gets the compressor ratio (N:1)
+         * @return compressor ratio (N:1)
          */
         public float getRatio() { return mRatio; }
         /**
-         * sets compressor ratio (1:N)
-         * @param ratio desired for the compressor (1:N)
+         * sets compressor ratio (N:1)
+         * @param ratio desired for the compressor (N:1)
          */
         public void setRatio(float ratio) { mRatio = ratio; }
         /**
@@ -670,13 +670,13 @@
         public void setNoiseGateThreshold(float noiseGateThreshold) {
             mNoiseGateThreshold = noiseGateThreshold; }
         /**
-         * gets Expander ratio (N:1) for signals below the Noise Gate Threshold.
-         * @return Expander ratio (N:1)
+         * gets Expander ratio (1:N) for signals below the Noise Gate Threshold.
+         * @return Expander ratio (1:N)
          */
         public float getExpanderRatio() { return mExpanderRatio; }
         /**
-         * sets Expander ratio (N:1) for signals below the Noise Gate Threshold.
-         * @param expanderRatio desired expander ratio (N:1)
+         * sets Expander ratio (1:N) for signals below the Noise Gate Threshold.
+         * @param expanderRatio desired expander ratio (1:N)
          */
         public void setExpanderRatio(float expanderRatio) { mExpanderRatio = expanderRatio; }
         /**
@@ -909,7 +909,7 @@
          * same linkGroup index will react together.
          * @param attackTime Attack Time for limiter compressor in milliseconds (ms)
          * @param releaseTime Release Time for limiter compressor in milliseconds (ms)
-         * @param ratio Limiter Compressor ratio (1:N)
+         * @param ratio Limiter Compressor ratio (N:1) (input:output)
          * @param threshold Limiter Compressor threshold measured in decibels (dB) from 0 dB Full
          * Scale (dBFS).
          * @param postGain Gain applied to the signal AFTER compression.
@@ -985,13 +985,13 @@
          */
         public void setReleaseTime(float releaseTime) { mReleaseTime = releaseTime; }
         /**
-         * gets the limiter compressor ratio (1:N)
-         * @return limiter compressor ratio (1:N)
+         * gets the limiter compressor ratio (N:1)
+         * @return limiter compressor ratio (N:1)
          */
         public float getRatio() { return mRatio; }
         /**
-         * sets limiter compressor ratio (1:N)
-         * @param ratio desired for the limiter compressor (1:N)
+         * sets limiter compressor ratio (N:1)
+         * @param ratio desired for the limiter compressor (N:1)
          */
         public void setRatio(float ratio) { mRatio = ratio; }
         /**
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_ImageWriter.cpp b/media/jni/android_media_ImageWriter.cpp
index 11659e4..f8f7a90 100644
--- a/media/jni/android_media_ImageWriter.cpp
+++ b/media/jni/android_media_ImageWriter.cpp
@@ -25,11 +25,14 @@
 #include <gui/Surface.h>
 #include <android_runtime/AndroidRuntime.h>
 #include <android_runtime/android_view_Surface.h>
+#include <android_runtime/android_hardware_HardwareBuffer.h>
+#include <private/android/AHardwareBufferHelpers.h>
 #include <jni.h>
 #include <nativehelper/JNIHelp.h>
 
 #include <stdint.h>
 #include <inttypes.h>
+#include <android/hardware_buffer_jni.h>
 
 #define IMAGE_BUFFER_JNI_ID           "mNativeBuffer"
 #define IMAGE_FORMAT_UNKNOWN          0 // This is the same value as ImageFormat#UNKNOWN.
@@ -701,6 +704,20 @@
     return static_cast<jint>(publicFmt);
 }
 
+static jobject Image_getHardwareBuffer(JNIEnv* env, jobject thiz) {
+    GraphicBuffer* buffer;
+    Image_getNativeContext(env, thiz, &buffer, NULL);
+    if (buffer == NULL) {
+        jniThrowException(env, "java/lang/IllegalStateException",
+                "Image is not initialized");
+        return NULL;
+    }
+    AHardwareBuffer* b = AHardwareBuffer_from_GraphicBuffer(buffer);
+    // don't user the public AHardwareBuffer_toHardwareBuffer() because this would force us
+    // to link against libandroid.so
+    return android_hardware_HardwareBuffer_createFromAHardwareBuffer(env, b);
+}
+
 static void Image_setFenceFd(JNIEnv* env, jobject thiz, int fenceFd) {
     ALOGV("%s:", __FUNCTION__);
     env->SetIntField(thiz, gSurfaceImageClassInfo.mNativeFenceFd, reinterpret_cast<jint>(fenceFd));
@@ -818,10 +835,12 @@
 
 static JNINativeMethod gImageMethods[] = {
     {"nativeCreatePlanes",      "(II)[Landroid/media/ImageWriter$WriterSurfaceImage$SurfacePlane;",
-                                                              (void*)Image_createSurfacePlanes },
-    {"nativeGetWidth",         "()I",                         (void*)Image_getWidth },
-    {"nativeGetHeight",        "()I",                         (void*)Image_getHeight },
-    {"nativeGetFormat",        "()I",                         (void*)Image_getFormat },
+                                                               (void*)Image_createSurfacePlanes },
+    {"nativeGetWidth",          "()I",                         (void*)Image_getWidth },
+    {"nativeGetHeight",         "()I",                         (void*)Image_getHeight },
+    {"nativeGetFormat",         "()I",                         (void*)Image_getFormat },
+    {"nativeGetHardwareBuffer", "()Landroid/hardware/HardwareBuffer;",
+                                                               (void*)Image_getHardwareBuffer },
 };
 
 int register_android_media_ImageWriter(JNIEnv *env) {
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/media/tests/MediaFrameworkTest/AndroidManifest.xml b/media/tests/MediaFrameworkTest/AndroidManifest.xml
index 3185ea2..e50a375 100644
--- a/media/tests/MediaFrameworkTest/AndroidManifest.xml
+++ b/media/tests/MediaFrameworkTest/AndroidManifest.xml
@@ -24,7 +24,7 @@
     <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
     <uses-permission android:name="android.permission.WAKE_LOCK" />
 
-    <application>
+    <application android:networkSecurityConfig="@xml/network_security_config">
         <uses-library android:name="android.test.runner" />
         <activity android:label="@string/app_name"
                 android:name="MediaFrameworkTest"
diff --git a/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml b/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml
new file mode 100644
index 0000000..c15c09c
--- /dev/null
+++ b/media/tests/MediaFrameworkTest/res/xml/network_security_config.xml
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+    <base-config cleartextTrafficPermitted="true"/>
+</network-security-config>
diff --git a/native/graphics/jni/Android.bp b/native/graphics/jni/Android.bp
index 0704e35..9426148 100644
--- a/native/graphics/jni/Android.bp
+++ b/native/graphics/jni/Android.bp
@@ -33,6 +33,7 @@
     arch: {
         arm: {
             // TODO: This is to work around b/24465209. Remove after root cause is fixed
+            pack_relocations: false,
             ldflags: ["-Wl,--hash-style=both"],
         },
     },
diff --git a/obex/Android.bp b/obex/Android.bp
new file mode 100644
index 0000000..6558eb3
--- /dev/null
+++ b/obex/Android.bp
@@ -0,0 +1,21 @@
+//
+// 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.
+//
+
+java_sdk_library {
+    name: "javax.obex",
+    srcs: ["javax/**/*.java"],
+    api_packages: ["javax.obex"],
+}
diff --git a/obex/Android.mk b/obex/Android.mk
deleted file mode 100644
index e7c1fd3..0000000
--- a/obex/Android.mk
+++ /dev/null
@@ -1,20 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obex
-
-include $(BUILD_JAVA_LIBRARY)
-
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_SRC_FILES := $(call all-subdir-java-files)
-
-LOCAL_MODULE:= javax.obexstatic
-
-include $(BUILD_STATIC_JAVA_LIBRARY)
\ No newline at end of file
diff --git a/obex/CleanSpec.mk b/obex/CleanSpec.mk
new file mode 100644
index 0000000..c104234
--- /dev/null
+++ b/obex/CleanSpec.mk
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+# runtime lib is renamed from javax.obex.jar to javax.obex.impl.jar
+$(call add-clean-step, rm -rf $(PRODUCT_OUT)/system/framework/javax.obex.jar)
diff --git a/obex/api/current.txt b/obex/api/current.txt
new file mode 100644
index 0000000..1cd562f
--- /dev/null
+++ b/obex/api/current.txt
@@ -0,0 +1,12 @@
+package javax.obex {
+
+  public class ObexPacket {
+    method public static javax.obex.ObexPacket read(java.io.InputStream) throws java.io.IOException;
+    method public static javax.obex.ObexPacket read(int, java.io.InputStream) throws java.io.IOException;
+    field public int mHeaderId;
+    field public int mLength;
+    field public byte[] mPayload;
+  }
+
+}
+
diff --git a/obex/api/removed.txt b/obex/api/removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/removed.txt
diff --git a/obex/api/system-current.txt b/obex/api/system-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-current.txt
diff --git a/obex/api/system-removed.txt b/obex/api/system-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/system-removed.txt
diff --git a/obex/api/test-current.txt b/obex/api/test-current.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-current.txt
diff --git a/obex/api/test-removed.txt b/obex/api/test-removed.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/obex/api/test-removed.txt
diff --git a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
index db776c6..9f89d3c 100644
--- a/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
+++ b/packages/CaptivePortalLogin/src/com/android/captiveportallogin/CaptivePortalLoginActivity.java
@@ -16,6 +16,9 @@
 
 package com.android.captiveportallogin;
 
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
+import static android.net.captiveportal.CaptivePortalProbeSpec.HTTP_LOCATION_HEADER_NAME;
+
 import android.app.Activity;
 import android.app.LoadedApk;
 import android.content.Context;
@@ -29,6 +32,7 @@
 import android.net.NetworkRequest;
 import android.net.Proxy;
 import android.net.Uri;
+import android.net.captiveportal.CaptivePortalProbeSpec;
 import android.net.dns.ResolvUtil;
 import android.net.http.SslError;
 import android.net.wifi.WifiInfo;
@@ -85,6 +89,7 @@
     };
 
     private URL mUrl;
+    private CaptivePortalProbeSpec mProbeSpec;
     private String mUserAgent;
     private Network mNetwork;
     private CaptivePortal mCaptivePortal;
@@ -118,6 +123,14 @@
             Log.d(TAG, String.format("onCreate for %s", mUrl.toString()));
         }
 
+        final String spec = getIntent().getStringExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC);
+        try {
+            mProbeSpec = CaptivePortalProbeSpec.parseSpecOrNull(spec);
+        } catch (Exception e) {
+            // Make extra sure that invalid configurations do not cause crashes
+            mProbeSpec = null;
+        }
+
         // Also initializes proxy system properties.
         mCm.bindProcessToNetwork(mNetwork);
         mCm.setProcessDefaultNetworkForHostResolution(
@@ -329,6 +342,7 @@
                 }
                 HttpURLConnection urlConnection = null;
                 int httpResponseCode = 500;
+                String locationHeader = null;
                 try {
                     urlConnection = (HttpURLConnection) network.openConnection(mUrl);
                     urlConnection.setInstanceFollowRedirects(false);
@@ -343,6 +357,7 @@
 
                     urlConnection.getInputStream();
                     httpResponseCode = urlConnection.getResponseCode();
+                    locationHeader = urlConnection.getHeaderField(HTTP_LOCATION_HEADER_NAME);
                     if (DBG) {
                         Log.d(TAG, "probe at " + mUrl +
                                 " ret=" + httpResponseCode +
@@ -353,13 +368,20 @@
                 } finally {
                     if (urlConnection != null) urlConnection.disconnect();
                 }
-                if (httpResponseCode == 204) {
+                if (isDismissed(httpResponseCode, locationHeader, mProbeSpec)) {
                     done(Result.DISMISSED);
                 }
             }
         }).start();
     }
 
+    private static boolean isDismissed(
+            int httpResponseCode, String locationHeader, CaptivePortalProbeSpec probeSpec) {
+        return (probeSpec != null)
+                ? probeSpec.getResult(httpResponseCode, locationHeader).isSuccessful()
+                : (httpResponseCode == 204);
+    }
+
     private class MyWebViewClient extends WebViewClient {
         private static final String INTERNAL_ASSETS = "file:///android_asset/";
 
diff --git a/packages/CtsShim/build/Android.mk b/packages/CtsShim/build/Android.mk
index 6186a78..e645adc 100644
--- a/packages/CtsShim/build/Android.mk
+++ b/packages/CtsShim/build/Android.mk
@@ -66,10 +66,11 @@
 LOCAL_MULTILIB := both
 LOCAL_JNI_SHARED_LIBRARIES := libshim_jni
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # out/target/common/obj/APPS/CtsShimPriv_intermediates/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
@@ -111,10 +112,11 @@
 
 LOCAL_MANIFEST_FILE := shim/AndroidManifest.xml
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # frameworks/base/packages/CtsShim/build/shim/AndroidManifest.xml:25: error: unexpected element <restrict-update> found in <manifest>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
 
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/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
index ee24bd0..8a1c4ef 100644
--- a/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
+++ b/packages/SettingsLib/src/com/android/settingslib/fuelgauge/PowerWhitelistBackend.java
@@ -16,17 +16,22 @@
 
 package com.android.settingslib.fuelgauge;
 
+import android.content.ComponentName;
+import android.content.Context;
 import android.content.pm.PackageManager;
 import android.os.IDeviceIdleController;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.UserHandle;
-import androidx.annotation.VisibleForTesting;
+import android.telecom.DefaultDialerManager;
+import android.text.TextUtils;
 import android.util.ArraySet;
 import android.util.Log;
 
+import com.android.internal.telephony.SmsApplication;
 import com.android.internal.util.ArrayUtils;
 
+import androidx.annotation.VisibleForTesting;
+
 /**
  * Handles getting/changing the whitelist for the exceptions to battery saving features.
  */
@@ -38,19 +43,20 @@
 
     private static PowerWhitelistBackend sInstance;
 
+    private final Context mAppContext;
     private final IDeviceIdleController mDeviceIdleService;
     private final ArraySet<String> mWhitelistedApps = new ArraySet<>();
     private final ArraySet<String> mSysWhitelistedApps = new ArraySet<>();
     private final ArraySet<String> mSysWhitelistedAppsExceptIdle = new ArraySet<>();
 
-    public PowerWhitelistBackend() {
-        mDeviceIdleService = IDeviceIdleController.Stub.asInterface(
-                ServiceManager.getService(DEVICE_IDLE_SERVICE));
-        refreshList();
+    public PowerWhitelistBackend(Context context) {
+        this(context, IDeviceIdleController.Stub.asInterface(
+                ServiceManager.getService(DEVICE_IDLE_SERVICE)));
     }
 
     @VisibleForTesting
-    PowerWhitelistBackend(IDeviceIdleController deviceIdleService) {
+    PowerWhitelistBackend(Context context, IDeviceIdleController deviceIdleService) {
+        mAppContext = context.getApplicationContext();
         mDeviceIdleService = deviceIdleService;
         refreshList();
     }
@@ -64,7 +70,27 @@
     }
 
     public boolean isWhitelisted(String pkg) {
-        return mWhitelistedApps.contains(pkg);
+        if (mWhitelistedApps.contains(pkg)) {
+            return true;
+        }
+
+        // Additionally, check if pkg is default dialer/sms. They are considered essential apps and
+        // should be automatically whitelisted (otherwise user may be able to set restriction on
+        // them, leading to bad device behavior.)
+        if (!mAppContext.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {
+            return false;
+        }
+        final ComponentName defaultSms = SmsApplication.getDefaultSmsApplication(mAppContext,
+                true /* updateIfNeeded */);
+        if (defaultSms != null && TextUtils.equals(pkg, defaultSms.getPackageName())) {
+            return true;
+        }
+
+        final String defaultDialer = DefaultDialerManager.getDefaultDialerApplication(mAppContext);
+        if (TextUtils.equals(pkg, defaultDialer)) {
+            return true;
+        }
+        return false;
     }
 
     public boolean isWhitelisted(String[] pkgs) {
@@ -120,16 +146,19 @@
         mSysWhitelistedApps.clear();
         mSysWhitelistedAppsExceptIdle.clear();
         mWhitelistedApps.clear();
+        if (mDeviceIdleService == null) {
+            return;
+        }
         try {
-            String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
+            final String[] whitelistedApps = mDeviceIdleService.getFullPowerWhitelist();
             for (String app : whitelistedApps) {
                 mWhitelistedApps.add(app);
             }
-            String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
+            final String[] sysWhitelistedApps = mDeviceIdleService.getSystemPowerWhitelist();
             for (String app : sysWhitelistedApps) {
                 mSysWhitelistedApps.add(app);
             }
-            String[] sysWhitelistedAppsExceptIdle =
+            final String[] sysWhitelistedAppsExceptIdle =
                     mDeviceIdleService.getSystemPowerWhitelistExceptIdle();
             for (String app : sysWhitelistedAppsExceptIdle) {
                 mSysWhitelistedAppsExceptIdle.add(app);
@@ -139,9 +168,9 @@
         }
     }
 
-    public static PowerWhitelistBackend getInstance() {
+    public static PowerWhitelistBackend getInstance(Context context) {
         if (sInstance == null) {
-            sInstance = new PowerWhitelistBackend();
+            sInstance = new PowerWhitelistBackend(context);
         }
         return sInstance;
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 13f00a1..e609a40 100644
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -57,7 +57,7 @@
     private int mLevel = -1;
     private boolean mCharging;
     private boolean mPowerSaveEnabled;
-    private boolean mPowerSaveAsColorError = true;
+    protected boolean mPowerSaveAsColorError = true;
     private boolean mShowPercent;
 
     private static final boolean SINGLE_DIGIT_PERCENT = false;
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
index 0af2c05..a23eebc 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/fuelgauge/PowerWhitelistBackendTest.java
@@ -23,35 +23,52 @@
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.verify;
 
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
 import android.os.IDeviceIdleController;
 
 import com.android.settingslib.SettingsLibRobolectricTestRunner;
+import com.android.settingslib.testutils.shadow.ShadowDefaultDialerManager;
+import com.android.settingslib.testutils.shadow.ShadowSmsApplication;
 
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
+import org.robolectric.RuntimeEnvironment;
+import org.robolectric.annotation.Config;
+import org.robolectric.shadow.api.Shadow;
+import org.robolectric.shadows.ShadowPackageManager;
 
 @RunWith(SettingsLibRobolectricTestRunner.class)
+@Config(shadows = {ShadowDefaultDialerManager.class, ShadowSmsApplication.class})
 public class PowerWhitelistBackendTest {
 
     private static final String PACKAGE_ONE = "com.example.packageone";
     private static final String PACKAGE_TWO = "com.example.packagetwo";
 
-    private PowerWhitelistBackend mPowerWhitelistBackend;
     @Mock
     private IDeviceIdleController mDeviceIdleService;
 
+    private PowerWhitelistBackend mPowerWhitelistBackend;
+    private ShadowPackageManager mPackageManager;
+    private Context mContext;
+
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
         doReturn(new String[] {}).when(mDeviceIdleService).getFullPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelist();
         doReturn(new String[] {}).when(mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         doNothing().when(mDeviceIdleService).addPowerSaveWhitelistApp(anyString());
         doNothing().when(mDeviceIdleService).removePowerSaveWhitelistApp(anyString());
-        mPowerWhitelistBackend = new PowerWhitelistBackend(mDeviceIdleService);
+        mPackageManager = Shadow.extract(mContext.getPackageManager());
+        mPackageManager.setSystemFeature(PackageManager.FEATURE_TELEPHONY, true);
+
+        mPowerWhitelistBackend = new PowerWhitelistBackend(mContext, mDeviceIdleService);
     }
 
     @Test
@@ -61,8 +78,8 @@
 
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
 
         mPowerWhitelistBackend.addApp(PACKAGE_TWO);
 
@@ -70,15 +87,15 @@
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(
-                new String[]{PACKAGE_ONE, PACKAGE_TWO})).isTrue();
+                new String[] {PACKAGE_ONE, PACKAGE_TWO})).isTrue();
 
         mPowerWhitelistBackend.removeApp(PACKAGE_TWO);
 
         verify(mDeviceIdleService, atLeastOnce()).removePowerSaveWhitelistApp(PACKAGE_TWO);
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isTrue();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_ONE})).isTrue();
-        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[]{PACKAGE_TWO})).isFalse();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_ONE})).isTrue();
+        assertThat(mPowerWhitelistBackend.isWhitelisted(new String[] {PACKAGE_TWO})).isFalse();
 
         mPowerWhitelistBackend.removeApp(PACKAGE_ONE);
 
@@ -86,7 +103,23 @@
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_ONE)).isFalse();
         assertThat(mPowerWhitelistBackend.isWhitelisted(PACKAGE_TWO)).isFalse();
         assertThat(mPowerWhitelistBackend.isWhitelisted(
-                new String[]{PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+                new String[] {PACKAGE_ONE, PACKAGE_TWO})).isFalse();
+    }
+
+    @Test
+    public void isWhitelisted_shouldWhitelistDefaultSms() {
+        final String testSms = "com.android.test.defaultsms";
+        ShadowSmsApplication.setDefaultSmsApplication(new ComponentName(testSms, "receiver"));
+
+        assertThat(mPowerWhitelistBackend.isWhitelisted(testSms)).isTrue();
+    }
+
+    @Test
+    public void isWhitelisted_shouldWhitelistDefaultDialer() {
+        final String testDialer = "com.android.test.defaultdialer";
+        ShadowDefaultDialerManager.setDefaultDialerApplication(testDialer);
+
+        assertThat(mPowerWhitelistBackend.isWhitelisted(testDialer)).isTrue();
     }
 
     @Test
@@ -101,7 +134,7 @@
 
     @Test
     public void testIsSystemWhitelistedExceptIdle_onePackage() throws Exception {
-        doReturn(new String[]{PACKAGE_TWO}).when(
+        doReturn(new String[] {PACKAGE_TWO}).when(
                 mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         mPowerWhitelistBackend.refreshList();
 
@@ -111,7 +144,7 @@
 
     @Test
     public void testIsSystemWhitelistedExceptIdle_packageArray() throws Exception {
-        doReturn(new String[]{PACKAGE_TWO}).when(
+        doReturn(new String[] {PACKAGE_TWO}).when(
                 mDeviceIdleService).getSystemPowerWhitelistExceptIdle();
         mPowerWhitelistBackend.refreshList();
 
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
new file mode 100644
index 0000000..f4afdb1
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowDefaultDialerManager.java
@@ -0,0 +1,44 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.testutils.shadow;
+
+import android.content.Context;
+import android.telecom.DefaultDialerManager;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(DefaultDialerManager.class)
+public class ShadowDefaultDialerManager {
+
+    private static String sDefaultDailer;
+
+    @Resetter
+    public void reset() {
+        sDefaultDailer = null;
+    }
+
+    @Implementation
+    public static String getDefaultDialerApplication(Context context) {
+        return sDefaultDailer;
+    }
+
+    public static void setDefaultDialerApplication(String dialer) {
+        sDefaultDailer = dialer;
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
new file mode 100644
index 0000000..dd7b007
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/testutils/shadow/ShadowSmsApplication.java
@@ -0,0 +1,46 @@
+/*
+ * 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.
+ */
+
+package com.android.settingslib.testutils.shadow;
+
+import android.content.ComponentName;
+import android.content.Context;
+
+import com.android.internal.telephony.SmsApplication;
+
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+import org.robolectric.annotation.Resetter;
+
+@Implements(SmsApplication.class)
+public class ShadowSmsApplication {
+
+    private static ComponentName sDefaultSmsApplication;
+
+    @Resetter
+    public void reset() {
+        sDefaultSmsApplication = null;
+    }
+
+    @Implementation
+    public static ComponentName getDefaultSmsApplication(Context context, boolean updateIfNeeded) {
+        return sDefaultSmsApplication;
+    }
+
+    public static void setDefaultSmsApplication(ComponentName cn) {
+        sDefaultSmsApplication = cn;
+    }
+}
\ No newline at end of file
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 28e8db9..e1a602b 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -214,4 +214,7 @@
 
     <!-- Default for Settings.Global.BACKUP_AGENT_TIMEOUT_PARAMETERS -->
     <string name="def_backup_agent_timeout_parameters"></string>
+
+    <!-- Default for Settings.System.VIBRATE_WHEN_RINGING -->
+    <bool name="def_vibrate_when_ringing">false</bool>
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 85bbd59..960d305 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 = 169;
 
             private final int mUserId;
 
@@ -3792,6 +3792,34 @@
                     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;
+                }
+
+                if (currentVersion == 168) {
+                    // Version 168: by default, vibrate for phone calls
+                    final SettingsState systemSettings = getSystemSettingsLocked(userId);
+                    final Setting currentSetting = systemSettings.getSettingLocked(
+                            Settings.System.VIBRATE_WHEN_RINGING);
+                    if (currentSetting.isNull()) {
+                        systemSettings.insertSettingLocked(
+                                Settings.System.VIBRATE_WHEN_RINGING,
+                                getContext().getResources().getBoolean(
+                                        R.bool.def_vibrate_when_ringing) ? "1" : "0",
+                                null, true, SettingsState.SYSTEM_PACKAGE_NAME);
+                    }
+                    currentVersion = 169;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 if (currentVersion != newVersion) {
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
index 5713dc6..b738d77 100644
--- a/packages/Shell/Android.mk
+++ b/packages/Shell/Android.mk
@@ -12,7 +12,8 @@
 
 LOCAL_AIDL_INCLUDES = frameworks/native/cmds/dumpstate/binder
 
-LOCAL_STATIC_JAVA_LIBRARIES := android-support-v4
+LOCAL_STATIC_ANDROID_LIBRARIES := androidx.legacy_legacy-support-v4
+LOCAL_USE_AAPT2 := true
 
 LOCAL_PACKAGE_NAME := Shell
 LOCAL_PRIVATE_PLATFORM_APIS := true
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index b4f331d..8a5cb4a 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -157,7 +157,7 @@
                  android:defaultToDeviceProtectedStorage="true"
                  android:directBootAware="true">
         <provider
-            android:name="android.support.v4.content.FileProvider"
+            android:name="androidx.core.content.FileProvider"
             android:authorities="com.android.shell"
             android:grantUriPermissions="true"
             android:exported="false">
diff --git a/packages/Shell/src/com/android/shell/BugreportProgressService.java b/packages/Shell/src/com/android/shell/BugreportProgressService.java
index 600f0dc..4fc190d 100644
--- a/packages/Shell/src/com/android/shell/BugreportProgressService.java
+++ b/packages/Shell/src/com/android/shell/BugreportProgressService.java
@@ -88,7 +88,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.os.Vibrator;
-import android.support.v4.content.FileProvider;
+import androidx.core.content.FileProvider;
 import android.text.TextUtils;
 import android.text.format.DateUtils;
 import android.util.Log;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index a92df74..8eee0d5 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -211,6 +211,8 @@
     <!-- Permission necessary to change car audio volume through CarAudioManager -->
     <uses-permission android:name="android.car.permission.CAR_CONTROL_AUDIO_VOLUME" />
 
+    <uses-permission android:name="android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS" />
+
     <application
         android:name=".SystemUIApplication"
         android:persistent="true"
diff --git a/packages/SystemUI/res-keyguard/values/dimens.xml b/packages/SystemUI/res-keyguard/values/dimens.xml
index d628ca8..787f91e 100644
--- a/packages/SystemUI/res-keyguard/values/dimens.xml
+++ b/packages/SystemUI/res-keyguard/values/dimens.xml
@@ -53,6 +53,7 @@
     <dimen name="widget_big_font_size">64dp</dimen>
     <!-- Clock with header -->
     <dimen name="widget_small_font_size">24dp</dimen>
+    <dimen name="widget_small_font_stroke">0.6dp</dimen>
     <!-- Dash between clock and header -->
     <dimen name="widget_separator_width">12dp</dimen>
     <dimen name="widget_separator_thickness">1dp</dimen>
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
deleted file mode 100644
index aa9f6d4..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 0a6074b..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 151caea..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 64bc40a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index d7f9449..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index 7c65703..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index eea819a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 504ceb7..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png
deleted file mode 100755
index 0622ddc..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index fb44f22a..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
deleted file mode 100644
index 613afce..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index a665e23..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 8e7d8cb..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 456a68f..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
deleted file mode 100644
index 72b2b21..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 4f65660..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index eb80426..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index c57face..0000000
--- a/packages/SystemUI/res/drawable-hdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..0899d35
--- /dev/null
+++ b/packages/SystemUI/res/drawable-hdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png
deleted file mode 100755
index c03ad20..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index bbaab44..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index fb854ec..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 75d184a..0000000
--- a/packages/SystemUI/res/drawable-land-hdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png
deleted file mode 100755
index bfe2b4a..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index dba0040..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 9e0af28..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 7c00bd5d..0000000
--- a/packages/SystemUI/res/drawable-land-xhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index 5ed0ee8..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 2b64b80..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 81b4466..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 724aa9e..0000000
--- a/packages/SystemUI/res/drawable-land-xxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index d181162..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 151a3c0..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 7ba0d1b..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index a175ccb..0000000
--- a/packages/SystemUI/res/drawable-land-xxxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png
deleted file mode 100755
index 236b70a..0000000
--- a/packages/SystemUI/res/drawable-land/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-land/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-land/ic_sysbar_docked_dark.png
deleted file mode 100644
index 3456a97..0000000
--- a/packages/SystemUI/res/drawable-land/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
deleted file mode 100644
index 2fcfdde..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 45ce1d4..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 6da0c9e..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-hdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 48708a5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 71e8959..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index bb7ae26..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-mdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back.png
deleted file mode 100644
index 74f9256..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index c3aea46..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-hdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 4de10b6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 470b3e2..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-mdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 965d2f5..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index e7137c6..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back.png
deleted file mode 100644
index a123262..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 03dec15..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back.png
deleted file mode 100644
index 0a95ddd..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index e1ca853..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 3d73184..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 32b9ded..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index ed1949c7..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
deleted file mode 100644
index 786935d..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 2d62a80..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index a52e5b1..0000000
--- a/packages/SystemUI/res/drawable-ldrtl-xxhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 34a11df..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 5383215..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 1c1e78c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 3a22912..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index d888869..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index dc3b25c..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index d4e5a94..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 0e693f7..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png
deleted file mode 100755
index 93d1905..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index c7e4731..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
deleted file mode 100644
index 7c25fc5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index d2949f3..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 0757799..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 4f07ec1..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
deleted file mode 100644
index 35e7af4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 06e4c26..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index 1ee9cf5..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 1c855c4..0000000
--- a/packages/SystemUI/res/drawable-mdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..2266449
--- /dev/null
+++ b/packages/SystemUI/res/drawable-mdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back.png
deleted file mode 100644
index 1e2c751..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 0520c49..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index fac2da8..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 3dc2b88..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked.png
deleted file mode 100644
index 63739b9..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 2ba5d5b..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home.png
deleted file mode 100644
index bb24c8b..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 62dc2d9..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu.png
deleted file mode 100644
index 711fd7a5..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index e718b7a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent.png
deleted file mode 100644
index bbb00a0..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 469800a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-hdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked.png
deleted file mode 100644
index 43f77c0..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 42863c6..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-hdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked.png
deleted file mode 100644
index 872af09..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index d9ec9d5..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-mdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png
deleted file mode 100644
index ea7ac93..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 8ee4e43..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index fe07f81..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index dfa8a97..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index 4193b21..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index d23abc7..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-land-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back.png
deleted file mode 100644
index 56c2638..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 8e56e9c..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index c3aa434..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 28a1465..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked.png
deleted file mode 100644
index 41a7209..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 0fc9677..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home.png
deleted file mode 100644
index faaef60..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 7b81eee..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu.png
deleted file mode 100644
index c8e40d0..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index a6483452..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent.png
deleted file mode 100644
index 2612485..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 7f74521..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-mdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 3b831a3..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 8c99455..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 3c37782..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png
deleted file mode 100644
index b2baa09..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index b78dc9c..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
deleted file mode 100644
index 37590a5..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 3a208aa..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png
deleted file mode 100644
index 4940d5c..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 625ba45..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 7ad2a29..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 604397e..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 274e5df..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 6fb19ae..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index 49d2c3a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index ac16895..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home.png
deleted file mode 100644
index 216f2c7..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index e69a037..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png
deleted file mode 100644
index 65a4354..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu.png
deleted file mode 100644
index a8c2786..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 8bddcd9..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index ca35888..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 38c5959..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back.png
deleted file mode 100644
index 4d23956..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index c6d7c98..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 74abc31..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 06c52aa..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100644
index 89bed92..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 7660997..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home.png
deleted file mode 100644
index 8d4f5f3..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 0d9ecc2..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu.png
deleted file mode 100644
index 83e96a2..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index d6bb8b1..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 636c0c1..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 298ef3a..0000000
--- a/packages/SystemUI/res/drawable-sw900dp-xxxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
deleted file mode 100644
index 987aac5..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index 371a84d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 433e5a74..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 360ed77..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index ba5b457..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index a55ea1d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index 407ef28..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 39cfbf2..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png
deleted file mode 100755
index 73ddde8..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 96cecc9..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
deleted file mode 100644
index 0e2a14d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 9ff9825..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index a7fd3a6..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index f2a1255..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
deleted file mode 100644
index 69a018d..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index e505f5e..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
deleted file mode 100644
index f810704..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 472c55b..0000000
--- a/packages/SystemUI/res/drawable-xhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..3328add
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
deleted file mode 100644
index be03cbe..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index c04d650..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index b6b1615..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 0f6d206..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index 5a7eec6..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index f7abb54..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index a1f44dc..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index 175a9ae..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index 1e84732..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 58bf920..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
deleted file mode 100644
index f16aa48..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index f47533ec..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index 0fb93ca..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index 1052940..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
deleted file mode 100644
index a37ca5d..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index f299d97..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 109aeed..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index 84d6dc8..0000000
--- a/packages/SystemUI/res/drawable-xxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..ed651da
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png
deleted file mode 100644
index a059704..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_dark.png
deleted file mode 100644
index d813bc7..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png
deleted file mode 100644
index 8f00a64..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_dark.png
deleted file mode 100644
index 30e8782..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
deleted file mode 100644
index d13c730..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
deleted file mode 100644
index 31c602e..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_ime_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
deleted file mode 100644
index ddbcb07..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
deleted file mode 100644
index ce91fcbb..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_back_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
deleted file mode 100755
index ee3ffde..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked_dark.png
deleted file mode 100644
index 83fc662..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_docked_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png
deleted file mode 100644
index 194d39f..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_dark.png
deleted file mode 100644
index 71101a1..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
deleted file mode 100644
index c606a58..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
deleted file mode 100644
index c2a5fef..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_home_quick_step_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_menu_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_menu_dark.png
deleted file mode 100644
index 4a477ad..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_menu_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png
deleted file mode 100644
index 046d850..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_dark.png b/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_dark.png
deleted file mode 100644
index bc24c00..0000000
--- a/packages/SystemUI/res/drawable-xxxhdpi/ic_sysbar_recent_dark.png
+++ /dev/null
Binary files differ
diff --git a/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
new file mode 100644
index 0000000..06e1202
--- /dev/null
+++ b/packages/SystemUI/res/drawable-xxxhdpi/qs_scrubber_track.9.png
Binary files differ
diff --git a/packages/SystemUI/res/drawable/car_add_circle_round.xml b/packages/SystemUI/res/drawable/car_add_circle_round.xml
index 5cf0c31..13c7dd1 100644
--- a/packages/SystemUI/res/drawable/car_add_circle_round.xml
+++ b/packages/SystemUI/res/drawable/car_add_circle_round.xml
@@ -1,4 +1,18 @@
 <?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.
+-->
 <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
     <item>
         <shape android:shape="oval">
diff --git a/packages/SystemUI/res/drawable/car_ic_add_white.xml b/packages/SystemUI/res/drawable/car_ic_add_white.xml
index f24771d..d681860 100644
--- a/packages/SystemUI/res/drawable/car_ic_add_white.xml
+++ b/packages/SystemUI/res/drawable/car_ic_add_white.xml
@@ -1,3 +1,17 @@
+<!-- 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.
+-->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
     android:width="@dimen/car_touch_target_size"
     android:height="@dimen/car_touch_target_size"
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_qs_auto_rotate.xml b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
index fba45d1..9c24c2c 100644
--- a/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_auto_rotate.xml
@@ -18,44 +18,9 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:height="48dp"
     android:width="48dp"
-    android:viewportHeight="48"
-    android:viewportWidth="48">
-    <group
-        android:name="device"
-        android:translateX="24"
-        android:translateY="24" >
-        <group
-            android:name="device_pivot"
-            android:translateX="-24.15"
-            android:translateY="-24.25" >
-            <group
-                android:name="device_0"
-                android:translateX="24.14999"
-                android:translateY="24.25" >
-                <path
-                    android:name="device_merged"
-                    android:pathData="M -3.5,-20.5 c -1.19999694824,-1.19999694824 -3.10000610352,-1.19999694824 -4.19999694824,0.0 c 0.0,0.0 -12.8000030518,12.6999969482 -12.8000030518,12.6999969482 c -1.19999694824,1.19999694824 -1.19999694824,3.10000610352 0.0,4.19999694824 c 0.0,0.0 24.0,24.0000152588 24.0,24.0000152588 c 1.19999694824,1.19999694824 3.10000610352,1.19999694824 4.19999694824,0.0 c 0.0,0.0 12.6999969482,-12.700012207 12.6999969482,-12.700012207 c 1.20001220703,-1.19999694824 1.20001220703,-3.09999084473 0.0,-4.19999694824 c 0.0,0.0 -23.8999938965,-24.0 -23.8999938965,-24.0 Z M 2.84999084473,15.5500183105 c 0.0,0.0 -18.6000061035,-18.5000457764 -18.6000061035,-18.5000457764 c 0.0,0.0 12.5999908447,-12.8000030518 12.5999908447,-12.8000030518 c 0.0,0.0 18.6000213623,18.5000457764 18.6000213623,18.5000457764 c 0.0,0.0 -12.6000061035,12.8000030518 -12.6000061035,12.8000030518 Z"
-                    android:fillColor="#FFFFFFFF" />
-            </group>
-        </group>
-    </group>
-    <group
-        android:name="arrows"
-        android:translateX="24"
-        android:translateY="24" >
-        <group
-            android:name="arrows_pivot"
-            android:translateX="-24.0798"
-            android:translateY="-24.23" >
-            <group
-                android:name="arrows_0"
-                android:translateX="12.2505"
-                android:translateY="37.2145" >
-                <path
-                    android:name="bottom_merged"
-                    android:pathData="M 20.7395019531,-31.9844970703 c 6.23999023438,2.83999633789 10.6999969482,8.7200012207 11.8399963379,15.7799987793 c 0.119995117188,0.699996948242 0.740005493164,1.2200012207 1.46099853516,1.2200012207 c 0.919998168945,0.0 1.6190032959,-0.84001159668 1.47900390625,-1.74000549316 c -1.75900268555,-10.3800048828 -9.75900268555,-19.1199951172 -22.5800018311,-20.1600036621 c -0.919998168945,-0.0800018310547 -1.43899536133,1.04000854492 -0.800003051758,1.70001220703 c 0.0,0.0 5.12100219727,5.11999511719 5.12100219727,5.11999511719 c 0.378997802734,0.380004882812 0.97900390625,0.380004882812 1.37899780273,0.020004272461 c 0.0,0.0 2.10000610352,-1.94000244141 2.10000610352,-1.94000244141 Z M 2.73950195312,6.01550292969 c -6.26000976562,-2.83999633789 -10.7200012207,-8.76000976562 -11.8399963379,-15.8600006104 c -0.118011474609,-0.667007446289 -0.702011108398,-1.15100097656 -1.38000488281,-1.13999938965 c -0.860000610352,0.0 -1.52000427246,0.759994506836 -1.38000488281,1.61999511719 c 1.54000854492,10.4000091553 9.5,19.2200012207 22.4199981689,20.2799987793 c 0.920013427734,0.0800018310547 1.44100952148,-1.03999328613 0.800003051758,-1.69999694824 c 0.0,0.0 -5.11999511719,-5.11999511719 -5.11999511719,-5.11999511719 c -0.380004882812,-0.376007080078 -0.988998413086,-0.385009765625 -1.38000488281,-0.0200042724609 c 0.0,0.0 -2.11999511719,1.94000244141 -2.11999511719,1.94000244141 Z"
-                    android:fillColor="#FFFFFFFF" />
-            </group>
-        </group>
-    </group>
+    android:viewportWidth="24.0"
+    android:viewportHeight="24.0">
+    <path
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M12.72,23H11C5.49,23 1,18.51 1,13h2c0,3.78 2.63,6.95 6.15,7.79L8.13,19L9.87,18L12.72,23zM13,1h-1.72l2.85,5L15.87,5l-1.02,-1.79C18.37,4.05 21,7.22 21,11h2C23,5.49 18.51,1 13,1zM10.23,6L18,13.76L13.77,18L6,10.24L10.23,6C10.23,6 10.23,6 10.23,6M10.23,4C9.72,4 9.21,4.2 8.82,4.59L4.59,8.82c-0.78,0.78 -0.78,2.04 0,2.82l7.77,7.77c0.39,0.39 0.9,0.59 1.41,0.59c0.51,0 1.02,-0.2 1.41,-0.59l4.24,-4.24c0.78,-0.78 0.78,-2.04 0,-2.82l-7.77,-7.77C11.26,4.2 10.75,4 10.23,4L10.23,4z"/>
 </vector>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml b/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
index 1603eba..8d569b2 100644
--- a/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
+++ b/packages/SystemUI/res/drawable/ic_sysbar_accessibility_button.xml
@@ -14,12 +14,11 @@
      See the License for the specific language governing permissions and
      limitations under the License.
 -->
-
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="24dp"
-        android:height="24dp"
-        android:viewportWidth="24"
-        android:viewportHeight="24">
+    android:width="21dp"
+    android:height="21dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
     <path
         android:pathData="M20.5,6c-2.61,0.7 -5.67,1 -8.5,1S6.11,6.7 3.5,6L3,8c1.86,0.5 4,0.83 6,1v13h2v-6h2v6h2V9c2,-0.17 4.14,-0.5 6,-1L20.5,6zM12,6c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2s-2,0.9 -2,2S10.9,6 12,6z"
         android:fillColor="?attr/singleToneColor"/>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back.xml b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
new file mode 100644
index 0000000..1448843
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="28dp"
+    android:height="28dp"
+    android:viewportWidth="28"
+    android:viewportHeight="28">
+
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M6.49,14.86c-0.66-0.39-0.66-1.34,0-1.73l6.02-3.53l5.89-3.46C19.11,5.73,20,6.26,20,7.1V14v6.9 c0,0.84-0.89,1.37-1.6,0.95l-5.89-3.46L6.49,14.86z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
new file mode 100644
index 0000000..93b2f9c8
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_back_quick_step.xml
@@ -0,0 +1,25 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="28dp"
+    android:height="28dp"
+    android:viewportWidth="28"
+    android:viewportHeight="28">
+    <path
+        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_docked.xml b/packages/SystemUI/res/drawable/ic_sysbar_docked.xml
new file mode 100644
index 0000000..693835f
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_docked.xml
@@ -0,0 +1,29 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="28dp"
+    android:height="28dp"
+    android:viewportWidth="28"
+    android:viewportHeight="28">
+
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M20.5,13h-13C6.67,13,6,12.33,6,11.5v-4C6,6.67,6.67,6,7.5,6h13C21.33,6,22,6.67,22,7.5v4 C22,12.33,21.33,13,20.5,13z" />
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M20.5,22h-13C6.67,22,6,21.33,6,20.5v-4C6,15.67,6.67,15,7.5,15h13c0.83,0,1.5,0.67,1.5,1.5v4 C22,21.33,21.33,22,20.5,22z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home.xml b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
new file mode 100644
index 0000000..a960af7
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_home.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<shape xmlns:android="http://schemas.android.com/apk/res/android"
+    android:shape="oval"
+    android:useLevel="false">
+
+    <solid android:color="?attr/singleToneColor" />
+
+    <size
+        android:height="14dp"
+        android:width="14dp" />
+</shape>
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_home_quick_step.xml b/packages/SystemUI/res/drawable/ic_sysbar_home_quick_step.xml
new file mode 100644
index 0000000..ba1236e
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_home_quick_step.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+     android:width="28dp"
+     android:height="28dp"
+     android:viewportWidth="28"
+     android:viewportHeight="28">
+
+     <path
+          android:fillColor="?attr/singleToneColor"
+          android:pathData="M23,19H5c-2.76,0-5-2.24-5-5l0,0c0-2.76,2.24-5,5-5h18c2.76,0,5,2.24,5,5l0,0C28,16.76,25.76,19,23,19z" />
+</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
new file mode 100644
index 0000000..d53c95b
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_menu.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="21dp"
+    android:height="21dp"
+    android:viewportWidth="28"
+    android:viewportHeight="28">
+
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M14,9.5c1.24,0,2.25-1.01,2.25-2.25S15.24,5,14,5s-2.25,1.01-2.25,2.25S12.76,9.5,14,9.5z M14,11.75 c-1.24,0-2.25,1.01-2.25,2.25s1.01,2.25,2.25,2.25s2.25-1.01,2.25-2.25S15.24,11.75,14,11.75z M14,18.5 c-1.24,0-2.25,1.01-2.25,2.25S12.76,23,14,23s2.25-1.01,2.25-2.25S15.24,18.5,14,18.5z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_sysbar_recent.xml b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
new file mode 100644
index 0000000..6b038d1
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_sysbar_recent.xml
@@ -0,0 +1,26 @@
+<?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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="28dp"
+    android:height="28dp"
+    android:viewportWidth="28"
+    android:viewportHeight="28">
+
+    <path
+        android:fillColor="?attr/singleToneColor"
+        android:pathData="M19.9,21.5H8.1c-0.88,0-1.6-0.72-1.6-1.6V8.1c0-0.88,0.72-1.6,1.6-1.6h11.8c0.88,0,1.6,0.72,1.6,1.6v11.8 C21.5,20.78,20.78,21.5,19.9,21.5z" />
+</vector>
\ No newline at end of file
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/back.xml b/packages/SystemUI/res/layout/back.xml
index 6843db9..4e8726b 100644
--- a/packages/SystemUI/res/layout/back.xml
+++ b/packages/SystemUI/res/layout/back.xml
@@ -22,10 +22,8 @@
     android:layout_height="match_parent"
     android:layout_weight="0"
     systemui:keyCode="4"
-    android:scaleType="fitCenter"
+    android:scaleType="center"
     android:contentDescription="@string/accessibility_back"
-    android:paddingTop="@dimen/home_padding"
-    android:paddingBottom="@dimen/home_padding"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
     />
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
index f34811e..8379dbb 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_pod.xml
@@ -23,15 +23,13 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:orientation="vertical"
-    android:gravity="center"
-    >
+    android:gravity="center">
 
     <ImageView android:id="@+id/user_avatar"
         android:layout_width="@dimen/car_user_switcher_image_avatar_size"
         android:layout_height="@dimen/car_user_switcher_image_avatar_size"
         android:background="@drawable/car_button_ripple_background_inverse"
-        android:gravity="center"
-        />
+        android:gravity="center"/>
 
     <TextView android:id="@+id/user_name"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
index bf5f188..2e1487c 100644
--- a/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
+++ b/packages/SystemUI/res/layout/car_fullscreen_user_switcher.xml
@@ -37,6 +37,7 @@
             android:id="@+id/user_grid"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
+            android:layout_marginTop="@dimen/car_user_switcher_margin_top"
             app:verticallyCenterListContent="true"
             app:dayNightStyle="force_night"
             app:showPagedListViewDivider="false"
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/home.xml b/packages/SystemUI/res/layout/home.xml
index 7b67b79..9586327 100644
--- a/packages/SystemUI/res/layout/home.xml
+++ b/packages/SystemUI/res/layout/home.xml
@@ -21,10 +21,8 @@
     android:layout_height="match_parent"
     android:layout_weight="0"
     systemui:keyCode="3"
-    android:scaleType="fitCenter"
+    android:scaleType="center"
     android:contentDescription="@string/accessibility_home"
-    android:paddingTop="@dimen/home_padding"
-    android:paddingBottom="@dimen/home_padding"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
     />
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/recent_apps.xml b/packages/SystemUI/res/layout/recent_apps.xml
index 6b08cea..870bcf7 100644
--- a/packages/SystemUI/res/layout/recent_apps.xml
+++ b/packages/SystemUI/res/layout/recent_apps.xml
@@ -21,10 +21,8 @@
     android:layout_width="@dimen/navigation_key_width"
     android:layout_height="match_parent"
     android:layout_weight="0"
-    android:scaleType="fitCenter"
+    android:scaleType="center"
     android:contentDescription="@string/accessibility_recent"
-    android:paddingTop="@dimen/home_padding"
-    android:paddingBottom="@dimen/home_padding"
     android:paddingStart="@dimen/navigation_key_padding"
     android:paddingEnd="@dimen/navigation_key_padding"
     />
diff --git a/packages/SystemUI/res/layout/recents_onboarding.xml b/packages/SystemUI/res/layout/recents_onboarding.xml
index 093a7ce1..adf1e74 100644
--- a/packages/SystemUI/res/layout/recents_onboarding.xml
+++ b/packages/SystemUI/res/layout/recents_onboarding.xml
@@ -23,7 +23,7 @@
 
     <LinearLayout
         android:layout_width="wrap_content"
-        android:layout_height="40dp"
+        android:layout_height="wrap_content"
         android:paddingStart="24dp"
         android:paddingEnd="4dp"
         android:background="@drawable/recents_onboarding_toast_rounded_background"
@@ -33,8 +33,9 @@
 
         <TextView
             android:id="@+id/onboarding_text"
-            android:layout_width="wrap_content"
+            android:layout_width="0dp"
             android:layout_height="wrap_content"
+            android:layout_weight="1"
             android:layout_gravity="center_vertical"
             android:textColor="@android:color/white"
             android:textSize="16sp"/>
diff --git a/packages/SystemUI/res/layout/remote_input.xml b/packages/SystemUI/res/layout/remote_input.xml
index e902c92..b5d48b4 100644
--- a/packages/SystemUI/res/layout/remote_input.xml
+++ b/packages/SystemUI/res/layout/remote_input.xml
@@ -42,7 +42,7 @@
             android:singleLine="true"
             android:ellipsize="start"
             android:inputType="textShortMessage|textAutoCorrect|textCapSentences"
-            android:imeOptions="actionSend" />
+            android:imeOptions="actionSend|flagNoExtractUi|flagNoFullscreen" />
 
     <FrameLayout
             android:layout_width="wrap_content"
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/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index c70e829..e67bb60 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -93,7 +93,7 @@
                     android:layout_gravity="center"
                     android:contentDescription="@string/accessibility_volume_settings"
                     android:background="@drawable/ripple_drawable_20dp"
-                    android:tint="?android:attr/textColorHint"
+                    android:tint="?android:attr/textColorSecondary"
                     android:soundEffectsEnabled="false" />
             </FrameLayout>
         </LinearLayout>
diff --git a/packages/SystemUI/res/values-ldrtl/strings.xml b/packages/SystemUI/res/values-ldrtl/strings.xml
new file mode 100644
index 0000000..c93da69
--- /dev/null
+++ b/packages/SystemUI/res/values-ldrtl/strings.xml
@@ -0,0 +1,22 @@
+<?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.
+ */
+-->
+<resources>
+    <!-- Recents: Text that shows above the navigation bar after launching several apps. [CHAR LIMIT=NONE] -->
+    <string name="recents_quick_scrub_onboarding">Drag left to quickly switch apps</string>
+</resources>
diff --git a/packages/SystemUI/res/values-sw600dp/dimens.xml b/packages/SystemUI/res/values-sw600dp/dimens.xml
index 923edc8..2dc6525 100644
--- a/packages/SystemUI/res/values-sw600dp/dimens.xml
+++ b/packages/SystemUI/res/values-sw600dp/dimens.xml
@@ -91,7 +91,4 @@
 
     <!-- The offsets the tasks animate from when recents is launched while docking -->
     <dimen name="recents_task_stack_animation_launched_while_docking_offset">192dp</dimen>
-
-    <!-- Home button padding for sizing -->
-    <dimen name="home_padding">0dp</dimen>
 </resources>
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/colors.xml b/packages/SystemUI/res/values/colors.xml
index 3472477..975055c 100644
--- a/packages/SystemUI/res/values/colors.xml
+++ b/packages/SystemUI/res/values/colors.xml
@@ -104,6 +104,9 @@
     <!-- The color of the navigation bar icons. Need to be in sync with ic_sysbar_* -->
     <color name="navigation_bar_icon_color">#E5FFFFFF</color>
 
+    <!-- The shadow color for light navigation bar icons. -->
+    <color name="nav_key_button_shadow_color">#30000000</color>
+
     <!-- Shadow color for the first pixels around the fake shadow for recents. -->
     <color name="fake_shadow_start_color">#44000000</color>
 
@@ -122,9 +125,6 @@
     <color name="light_mode_icon_color_dual_tone_background">#4dffffff</color>
     <color name="light_mode_icon_color_dual_tone_fill">#ffffff</color>
 
-    <color name="volume_settings_icon_color">#7fffffff</color>
-    <color name="volume_slider_inactive">@*android:color/quaternary_device_default_settings</color>
-
     <color name="docked_divider_background">#ff000000</color>
     <color name="docked_divider_handle">#ffffff</color>
     <drawable name="forced_resizable_background">#59000000</drawable>
@@ -138,7 +138,7 @@
     <color name="remote_input_accent">#eeeeee</color>
 
     <color name="quick_step_track_background_dark">#61000000</color>
-    <color name="quick_step_track_background_light">#4DFFFFFF</color>
+    <color name="quick_step_track_background_light">#33FFFFFF</color>
 
     <!-- Keyboard shortcuts colors -->
     <color name="ksh_application_group_color">#fff44336</color>
diff --git a/packages/SystemUI/res/values/colors_car.xml b/packages/SystemUI/res/values/colors_car.xml
index cb3abb9..49bfb25 100644
--- a/packages/SystemUI/res/values/colors_car.xml
+++ b/packages/SystemUI/res/values/colors_car.xml
@@ -25,4 +25,7 @@
     <color name="car_user_switcher_name_text_color">@color/car_body1_light</color>
     <color name="car_user_switcher_add_user_background_color">@color/car_dark_blue_grey_600</color>
     <color name="car_user_switcher_add_user_add_sign_color">@color/car_body1_light</color>
+
+    <!-- colors for volume dialog tint -->
+    <color name="car_volume_dialog_tint">@color/car_tint</color>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index fb3601c..5c0d5dd 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -367,6 +367,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 c1458b2..9a3bdf2 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -34,10 +34,10 @@
     <dimen name="status_bar_icon_size">@*android:dimen/status_bar_icon_size</dimen>
 
     <!-- Height of the battery icon in the status bar. -->
-    <dimen name="status_bar_battery_icon_height">14.5dp</dimen>
+    <dimen name="status_bar_battery_icon_height">13.0dp</dimen>
 
     <!-- Width of the battery icon in the status bar. -->
-    <dimen name="status_bar_battery_icon_width">9.5dp</dimen>
+    <dimen name="status_bar_battery_icon_width">8.5dp</dimen>
 
     <!-- The font size for the clock in the status bar. -->
     <dimen name="status_bar_clock_size">14sp</dimen>
@@ -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>
@@ -867,6 +867,8 @@
 
     <!-- The size of corner radius of the arrow in the onboarding toast. -->
     <dimen name="recents_onboarding_toast_arrow_corner_radius">2dp</dimen>
+    <!-- The start margin of quick scrub onboarding toast. -->
+    <dimen name="recents_quick_scrub_onboarding_margin_start">8dp</dimen>
 
     <!-- The min alpha to apply to a task affiliation group color. -->
     <item name="recents_task_affiliation_color_min_alpha_percentage" format="float" type="dimen">0.6</item>
@@ -938,11 +940,13 @@
     <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_thickness">2dp</dimen>
+    <dimen name="nav_quick_scrub_track_edge_padding">24dp</dimen>
+    <dimen name="nav_quick_scrub_track_thickness">10dp</dimen>
 
-    <!-- Home button padding for sizing -->
-    <dimen name="home_padding">16dp</dimen>
+    <!-- Navigation bar shadow params. -->
+    <dimen name="nav_key_button_shadow_offset_x">0dp</dimen>
+    <dimen name="nav_key_button_shadow_offset_y">1dp</dimen>
+    <dimen name="nav_key_button_shadow_radius">0.5dp</dimen>
 
     <!-- Smart reply button. Total height 48dp, visible height 32dp. -->
     <dimen name="smart_reply_button_spacing">8dp</dimen>
@@ -960,6 +964,10 @@
             add about 88dp of height to the notifications. -->
     <dimen name="smart_reply_button_max_height">100dp</dimen>
 
+    <!-- The extra height that we allow a notification with a remote input history to be taller than
+         the regular notification, when we have remote input history texts present. -->
+    <dimen name="remote_input_history_extra_height">60dp</dimen>
+
     <!-- Fingerprint Dialog values -->
     <dimen name="fingerprint_dialog_fp_icon_size">64dp</dimen>
     <dimen name="fingerprint_dialog_animation_translation_offset">350dp</dimen>
@@ -1001,4 +1009,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/dimens_car.xml b/packages/SystemUI/res/values/dimens_car.xml
index 8e17b52..afbe176 100644
--- a/packages/SystemUI/res/values/dimens_car.xml
+++ b/packages/SystemUI/res/values/dimens_car.xml
@@ -21,6 +21,7 @@
     <dimen name="car_user_switcher_image_avatar_size">@dimen/car_large_avatar_size</dimen>
     <dimen name="car_user_switcher_vertical_spacing_between_users">@dimen/car_padding_5</dimen>
     <dimen name="car_user_switcher_vertical_spacing_between_name_and_avatar">@dimen/car_padding_4</dimen>
+    <dimen name="car_user_switcher_margin_top">@dimen/car_padding_4</dimen>
 
     <dimen name="car_navigation_button_width">64dp</dimen>
     <dimen name="car_navigation_bar_width">760dp</dimen>
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/keyguard/KeyguardSliceView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
index b8776f7..5a84fa5 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSliceView.java
@@ -58,7 +58,7 @@
 
 import androidx.slice.Slice;
 import androidx.slice.SliceItem;
-import androidx.slice.SliceManager;
+import androidx.slice.SliceViewManager;
 import androidx.slice.core.SliceQuery;
 import androidx.slice.widget.ListContent;
 import androidx.slice.widget.RowContent;
@@ -84,10 +84,9 @@
     private LiveData<Slice> mLiveData;
     private int mIconSize;
     /**
-     * Listener called whenever the view contents change.
-     * Boolean will be true when the change happens animated.
+     * Runnable called whenever the view contents change.
      */
-    private Consumer<Boolean> mContentChangeListener;
+    private Runnable mContentChangeListener;
     private boolean mHasHeader;
     private Slice mSlice;
     private boolean mPulsing;
@@ -151,7 +150,9 @@
         if (mPulsing || mSlice == null) {
             mTitle.setVisibility(GONE);
             mRow.setVisibility(GONE);
-            mContentChangeListener.accept(getLayoutTransition() != null);
+            if (mContentChangeListener != null) {
+                mContentChangeListener.run();
+            }
             return;
         }
 
@@ -224,7 +225,7 @@
         }
 
         if (mContentChangeListener != null) {
-            mContentChangeListener.accept(getLayoutTransition() != null);
+            mContentChangeListener.run();
         }
     }
 
@@ -311,11 +312,10 @@
     }
 
     /**
-     * Listener that gets invoked every time the title or the row visibility changes.
-     * Parameter will be {@code true} whenever the change happens animated.
+     * Runnable that gets invoked every time the title or the row visibility changes.
      * @param contentChangeListener The listener.
      */
-    public void setContentChangeListener(Consumer<Boolean> contentChangeListener) {
+    public void setContentChangeListener(Runnable contentChangeListener) {
         mContentChangeListener = contentChangeListener;
     }
 
@@ -374,7 +374,7 @@
     }
 
     public void refresh() {
-        Slice slice = SliceManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
+        Slice slice = SliceViewManager.getInstance(getContext()).bindSlice(mKeyguardSliceUri);
         onChanged(slice);
     }
 
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
index 585797a..c521d59 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardStatusView.java
@@ -23,6 +23,7 @@
 import android.content.Context;
 import android.content.res.Resources;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.RemoteException;
@@ -75,7 +76,6 @@
     private float mDarkAmount = 0;
     private int mTextColor;
     private float mWidgetPadding;
-    private boolean mAnimateLayout;
     private int mLastLayoutHeight;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
@@ -179,10 +179,12 @@
         mVisibleInDoze = Sets.newArraySet(mClockView, mKeyguardSlice);
         mTextColor = mClockView.getCurrentTextColor();
 
+        int clockStroke = getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke);
+        mClockView.getPaint().setStrokeWidth(clockStroke);
         mClockView.addOnLayoutChangeListener(this);
         mClockSeparator.addOnLayoutChangeListener(this);
         mKeyguardSlice.setContentChangeListener(this::onSliceContentChanged);
-        onSliceContentChanged(false /* animated */);
+        onSliceContentChanged();
 
         boolean shouldMarquee = KeyguardUpdateMonitor.getInstance(mContext).isDeviceInteractive();
         setEnableMarquee(shouldMarquee);
@@ -196,8 +198,7 @@
         mClockView.setElegantTextHeight(false);
     }
 
-    private void onSliceContentChanged(boolean animated) {
-        mAnimateLayout = animated;
+    private void onSliceContentChanged() {
         boolean smallClock = mKeyguardSlice.hasHeader() || mPulsing;
         float clockScale = smallClock ? mSmallClockScale : 1;
 
@@ -225,9 +226,12 @@
         long duration = KeyguardSliceView.DEFAULT_ANIM_DURATION;
         long delay = smallClock ? 0 : duration / 4;
 
+        boolean shouldAnimate = mKeyguardSlice.getLayoutTransition() != null
+                && mKeyguardSlice.getLayoutTransition().isRunning();
         if (view == mClockView) {
             float clockScale = smallClock ? mSmallClockScale : 1;
-            if (mAnimateLayout) {
+            Paint.Style style = smallClock ? Paint.Style.FILL_AND_STROKE : Paint.Style.FILL;
+            if (shouldAnimate) {
                 mClockView.setY(oldTop + heightOffset);
                 mClockView.animate().cancel();
                 mClockView.animate()
@@ -238,16 +242,22 @@
                         .y(top)
                         .scaleX(clockScale)
                         .scaleY(clockScale)
+                        .withEndAction(() -> {
+                            mClockView.getPaint().setStyle(style);
+                            mClockView.invalidate();
+                        })
                         .start();
             } else {
                 mClockView.setY(top);
                 mClockView.setScaleX(clockScale);
                 mClockView.setScaleY(clockScale);
+                mClockView.getPaint().setStyle(style);
+                mClockView.invalidate();
             }
         } else if (view == mClockSeparator) {
             boolean hasSeparator = hasHeader && !mPulsing;
             float alpha = hasSeparator ? 1 : 0;
-            if (mAnimateLayout) {
+            if (shouldAnimate) {
                 boolean isAwake = mDarkAmount != 0;
                 mClockSeparator.setY(oldTop + heightOffset);
                 mClockSeparator.animate().cancel();
@@ -280,6 +290,8 @@
         if (mClockView != null) {
             mClockView.setTextSize(TypedValue.COMPLEX_UNIT_PX,
                     getResources().getDimensionPixelSize(R.dimen.widget_big_font_size));
+            mClockView.getPaint().setStrokeWidth(
+                    getResources().getDimensionPixelSize(R.dimen.widget_small_font_stroke));
         }
         if (mOwnerInfo != null) {
             mOwnerInfo.setTextSize(TypedValue.COMPLEX_UNIT_PX,
diff --git a/packages/SystemUI/src/com/android/systemui/Dependency.java b/packages/SystemUI/src/com/android/systemui/Dependency.java
index beb3c53..9c9f021 100644
--- a/packages/SystemUI/src/com/android/systemui/Dependency.java
+++ b/packages/SystemUI/src/com/android/systemui/Dependency.java
@@ -151,7 +151,6 @@
 
     @Override
     public void start() {
-        sDependency = this;
         // TODO: Think about ways to push these creation rules out of Dependency to cut down
         // on imports.
         mProviders.put(TIME_TICK_HANDLER, () -> {
@@ -331,6 +330,8 @@
 
         // Put all dependencies above here so the factory can override them if it wants.
         SystemUIFactory.getInstance().injectDependencies(mProviders, mContext);
+
+        sDependency = this;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
index 9b16eec..21393e4 100644
--- a/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
+++ b/packages/SystemUI/src/com/android/systemui/ScreenDecorations.java
@@ -22,8 +22,8 @@
 import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
-import static com.android.systemui.tuner.TunablePadding.FLAG_START;
 import static com.android.systemui.tuner.TunablePadding.FLAG_END;
+import static com.android.systemui.tuner.TunablePadding.FLAG_START;
 
 import android.annotation.Dimension;
 import android.app.Fragment;
@@ -66,6 +66,7 @@
 import com.android.systemui.tuner.TunablePadding;
 import com.android.systemui.tuner.TunerService;
 import com.android.systemui.tuner.TunerService.Tunable;
+import com.android.systemui.util.leak.RotationUtils;
 
 /**
  * An overlay that draws screen decorations in software (e.g for rounded corners or display cutout)
@@ -77,6 +78,9 @@
     private static final boolean DEBUG_SCREENSHOT_ROUNDED_CORNERS =
             SystemProperties.getBoolean("debug.screenshot_rounded_corners", false);
 
+    private DisplayManager mDisplayManager;
+    private DisplayManager.DisplayListener mDisplayListener;
+
     private int mRoundedDefault;
     private int mRoundedDefaultTop;
     private int mRoundedDefaultBottom;
@@ -84,7 +88,7 @@
     private View mBottomOverlay;
     private float mDensity;
     private WindowManager mWindowManager;
-    private boolean mLandscape;
+    private int mRotation;
 
     @Override
     public void start() {
@@ -104,6 +108,28 @@
         if (padding != 0) {
             setupPadding(padding);
         }
+
+        mDisplayListener = new DisplayManager.DisplayListener() {
+            @Override
+            public void onDisplayAdded(int displayId) {
+                // do nothing
+            }
+
+            @Override
+            public void onDisplayRemoved(int displayId) {
+                // do nothing
+            }
+
+            @Override
+            public void onDisplayChanged(int displayId) {
+                updateOrientation();
+            }
+        };
+
+        mRotation = -1;
+        mDisplayManager = (DisplayManager) mContext.getSystemService(
+                Context.DISPLAY_SERVICE);
+        mDisplayManager.registerDisplayListener(mDisplayListener, null);
     }
 
     private void setupDecorations() {
@@ -169,18 +195,22 @@
 
     @Override
     protected void onConfigurationChanged(Configuration newConfig) {
-        boolean newLanscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
-        if (newLanscape != mLandscape) {
-            mLandscape = newLanscape;
+        updateOrientation();
+        if (shouldDrawCutout() && mOverlay == null) {
+            setupDecorations();
+        }
+    }
+
+    protected void updateOrientation() {
+        int newRotation = RotationUtils.getExactRotation(mContext);
+        if (newRotation != mRotation) {
+            mRotation = newRotation;
 
             if (mOverlay != null) {
                 updateLayoutParams();
                 updateViews();
             }
         }
-        if (shouldDrawCutout() && mOverlay == null) {
-            setupDecorations();
-        }
     }
 
     private void updateViews() {
@@ -188,16 +218,28 @@
         View topRight = mOverlay.findViewById(R.id.right);
         View bottomLeft = mBottomOverlay.findViewById(R.id.left);
         View bottomRight = mBottomOverlay.findViewById(R.id.right);
-        if (mLandscape) {
-            // Flip corners
-            View tmp = topRight;
-            topRight = bottomLeft;
-            bottomLeft = tmp;
+
+        if (mRotation == RotationUtils.ROTATION_NONE) {
+            updateView(topLeft, Gravity.TOP | Gravity.LEFT, 0);
+            updateView(topRight, Gravity.TOP | Gravity.RIGHT, 90);
+            updateView(bottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(bottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_LANDSCAPE) {
+            updateView(topLeft, Gravity.TOP | Gravity.LEFT, 0);
+            updateView(topRight, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(bottomLeft, Gravity.TOP | Gravity.RIGHT, 90);;
+            updateView(bottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+        } else if (mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+            updateView(topLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(topRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
+            updateView(bottomLeft, Gravity.TOP | Gravity.LEFT, 0);
+            updateView(bottomRight, Gravity.TOP | Gravity.RIGHT, 90);
+        } else if (mRotation == RotationUtils.ROTATION_SEASCAPE) {
+            updateView(topLeft, Gravity.BOTTOM | Gravity.RIGHT, 180);
+            updateView(topRight, Gravity.TOP | Gravity.RIGHT, 90);
+            updateView(bottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
+            updateView(bottomRight, Gravity.TOP | Gravity.LEFT, 0);
         }
-        updateView(topLeft, Gravity.TOP | Gravity.LEFT, 0);
-        updateView(topRight, Gravity.TOP | Gravity.RIGHT, 90);
-        updateView(bottomLeft, Gravity.BOTTOM | Gravity.LEFT, 270);
-        updateView(bottomRight, Gravity.BOTTOM | Gravity.RIGHT, 180);
 
         updateWindowVisibilities();
     }
@@ -269,9 +311,14 @@
         }
 
         lp.setTitle("ScreenDecorOverlay");
-        lp.gravity = Gravity.TOP | Gravity.LEFT;
+        if (mRotation == RotationUtils.ROTATION_SEASCAPE
+                || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+            lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+        } else {
+            lp.gravity = Gravity.TOP | Gravity.LEFT;
+        }
         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
-        if (mLandscape) {
+        if (isLandscape(mRotation)) {
             lp.width = WRAP_CONTENT;
             lp.height = MATCH_PARENT;
         }
@@ -281,7 +328,12 @@
     private WindowManager.LayoutParams getBottomLayoutParams() {
         WindowManager.LayoutParams lp = getWindowLayoutParams();
         lp.setTitle("ScreenDecorOverlayBottom");
-        lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+        if (mRotation == RotationUtils.ROTATION_SEASCAPE
+                || mRotation == RotationUtils.ROTATION_UPSIDE_DOWN) {
+            lp.gravity = Gravity.TOP | Gravity.LEFT;
+        } else {
+            lp.gravity = Gravity.BOTTOM | Gravity.RIGHT;
+        }
         return lp;
     }
 
@@ -568,4 +620,9 @@
             return cutoutBounds;
         }
     }
+
+    private boolean isLandscape(int rotation) {
+        return rotation == RotationUtils.ROTATION_LANDSCAPE || rotation ==
+                RotationUtils.ROTATION_SEASCAPE;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
index e6ea2d8..6d79066 100644
--- a/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/SlicePermissionActivity.java
@@ -14,6 +14,8 @@
 
 package com.android.systemui;
 
+import static android.view.WindowManager.LayoutParams.PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS;
+
 import android.app.Activity;
 import android.app.AlertDialog;
 import android.app.slice.SliceManager;
@@ -66,7 +68,9 @@
                     .setNegativeButton(R.string.slice_permission_deny, this)
                     .setPositiveButton(R.string.slice_permission_allow, this)
                     .setOnDismissListener(this)
-                    .show();
+                    .create();
+            dialog.getWindow().addPrivateFlags(PRIVATE_FLAG_HIDE_NON_SYSTEM_OVERLAY_WINDOWS);
+            dialog.show();
             TextView t1 = dialog.getWindow().getDecorView().findViewById(R.id.text1);
             t1.setText(getString(R.string.slice_permission_text_1, app2));
             TextView t2 = dialog.getWindow().getDecorView().findViewById(R.id.text2);
diff --git a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
index 721890f..03a6398 100644
--- a/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/SystemUIFactory.java
@@ -56,6 +56,7 @@
 import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.SmartReplyConstants;
 
 import java.util.function.Consumer;
@@ -148,5 +149,7 @@
         providers.put(NotificationEntryManager.class, () -> new NotificationEntryManager(context));
         providers.put(KeyguardDismissUtil.class, KeyguardDismissUtil::new);
         providers.put(SmartReplyController.class, () -> new SmartReplyController());
+        providers.put(RemoteInputQuickSettingsDisabler.class,
+                () -> new RemoteInputQuickSettingsDisabler(context));
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
index 90140ff..f14d396 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeScreenState.java
@@ -42,7 +42,7 @@
      * hiding the wallpaper and changing the display mode is necessary to hide
      * the black frame that's inherent to hardware specs.
      */
-    public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 2000;
+    public static final int ENTER_DOZE_HIDE_WALLPAPER_DELAY = 4500;
 
     private final DozeMachine.Service mDozeService;
     private final Handler mHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
index 31d8cbb..ad84130 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMotionHelper.java
@@ -225,9 +225,10 @@
      */
     boolean shouldDismissPip() {
         Point displaySize = new Point();
-        mContext.getDisplay().getSize(displaySize);
-        if (mBounds.bottom > displaySize.y) {
-            float offscreenFraction = (float) (mBounds.bottom - displaySize.y) / mBounds.height();
+        mContext.getDisplay().getRealSize(displaySize);
+        final int y = displaySize.y - mStableInsets.bottom;
+        if (mBounds.bottom > y) {
+            float offscreenFraction = (float) (mBounds.bottom - y) / mBounds.height();
             return offscreenFraction >= DISMISS_OFFSCREEN_FRACTION;
         }
         return false;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
index 7afa82a..100751c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/PagedTileLayout.java
@@ -184,9 +184,15 @@
             return;
         }
         boolean selected = mLastExpansion == 1f;
+
+        // Disable accessibility temporarily while we update selected state purely for the
+        // marquee. This will ensure that accessibility doesn't announce the TYPE_VIEW_SELECTED
+        // event on any of the children.
+        setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);
         for (int i = 0; i < mPages.size(); i++) {
             mPages.get(i).setSelected(i == getCurrentItem() ? selected : false);
         }
+        setImportantForAccessibility(View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
     }
 
     public void setPageListener(PageListener listener) {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 67f1138..bd89ad1 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -35,6 +35,7 @@
 import android.view.ViewTreeObserver;
 import android.widget.FrameLayout.LayoutParams;
 
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.R.id;
@@ -43,6 +44,7 @@
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.CommandQueue;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.stack.StackStateAnimator;
 
 public class QSFragment extends Fragment implements QS, CommandQueue.Callbacks {
@@ -72,6 +74,9 @@
     private float mLastQSExpansion = -1;
     private boolean mQsDisabled;
 
+    private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
+            Dependency.get(RemoteInputQuickSettingsDisabler.class);
+
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
             Bundle savedInstanceState) {
@@ -191,6 +196,8 @@
 
     @Override
     public void disable(int state1, int state2, boolean animate) {
+        state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
         final boolean disabled = (state2 & DISABLE2_QUICK_SETTINGS) != 0;
         if (disabled == mQsDisabled) return;
         mQsDisabled = disabled;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
index 89f86c5..23e3f25 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/BatterySaverTile.java
@@ -110,7 +110,8 @@
 
         @Override
         public Drawable getDrawable(Context context) {
-            BatterySaverDrawable b = new BatterySaverDrawable(context, 0);
+            BatterySaverDrawable b =
+                    new BatterySaverDrawable(context, QSTileImpl.getColorForState(context, mState));
             b.mState = mState;
             final int pad = context.getResources()
                     .getDimensionPixelSize(R.dimen.qs_tile_divider_height);
@@ -130,11 +131,16 @@
             setPowerSave(true);
             setCharging(false);
             setPowerSaveAsColorError(false);
+            mPowerSaveAsColorError = true;
+            mFramePaint.setColor(0);
+            mPowersavePaint.setColor(frameColor);
+            mFramePaint.setStrokeWidth(mPowersavePaint.getStrokeWidth());
+            mPlusPaint.setColor(frameColor);
         }
 
         @Override
         protected int batteryColorForLevel(int level) {
-            return QSTileImpl.getColorForState(mContext, mState);
+            return 0;
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index 6fcb1c1..7e4acc2 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -123,10 +123,16 @@
      */
     class TaskStackListenerImpl extends SysUiTaskStackChangeListener {
 
+        private OverviewProxyService mOverviewProxyService;
+
+        public TaskStackListenerImpl() {
+            mOverviewProxyService = Dependency.get(OverviewProxyService.class);
+        }
+
         @Override
         public void onTaskStackChangedBackground() {
             // Skip background preloading recents in SystemUI if the overview services is bound
-            if (Dependency.get(OverviewProxyService.class).isEnabled()) {
+            if (mOverviewProxyService.isEnabled()) {
                 return;
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsOnboarding.java
index bcc33d2..8d8e206 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,11 +391,22 @@
         // 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());
+            final int gravity;
+            final int x;
+            if (stringRes == R.string.recents_swipe_up_onboarding) {
+                gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
+                x = 0;
+            } else {
+                int layoutDirection =
+                        mContext.getResources().getConfiguration().getLayoutDirection();
+                gravity = Gravity.BOTTOM | (layoutDirection == View.LAYOUT_DIRECTION_LTR
+                        ? Gravity.LEFT : Gravity.RIGHT);
+                x = mContext.getResources().getDimensionPixelSize(
+                        R.dimen.recents_quick_scrub_onboarding_margin_start);
+            }
+            mWindowManager.addView(mLayout, getWindowLayoutParams(gravity, x));
             mLayout.setAlpha(0);
             mLayout.animate()
                     .alpha(1f)
@@ -433,7 +432,6 @@
 
     public void hide(boolean animate) {
         if (mLayoutAttachedToWindow) {
-            Log.d(TAG, "Hide tip, animated: " + animate);
             if (animate) {
                 mLayout.animate()
                         .alpha(0f)
@@ -474,19 +472,19 @@
         pw.println("    }");
     }
 
-    private WindowManager.LayoutParams getWindowLayoutParams() {
+    private WindowManager.LayoutParams getWindowLayoutParams(int gravity, int x) {
         int flags = WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
                 | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
         final WindowManager.LayoutParams lp = new WindowManager.LayoutParams(
-                ViewGroup.LayoutParams.MATCH_PARENT,
                 ViewGroup.LayoutParams.WRAP_CONTENT,
-                0, -mNavBarHeight / 2,
+                ViewGroup.LayoutParams.WRAP_CONTENT,
+                x, -mNavBarHeight / 2,
                 WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL,
                 flags,
                 PixelFormat.TRANSLUCENT);
         lp.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_SHOW_FOR_ALL_USERS;
         lp.setTitle("RecentsOnboarding");
-        lp.gravity = Gravity.BOTTOM;
+        lp.gravity = gravity;
         return lp;
     }
 
@@ -495,7 +493,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 +504,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 +516,6 @@
     }
 
     private void setDismissedSwipeUpOnboardingCount(int dismissedSwipeUpOnboardingCount) {
-        Log.d(TAG, "setDismissedSwipeUpOnboardingCount: " + dismissedSwipeUpOnboardingCount);
         Prefs.putInt(mContext, DISMISSED_RECENTS_SWIPE_UP_ONBOARDING_COUNT,
                 dismissedSwipeUpOnboardingCount);
     }
@@ -531,8 +526,6 @@
 
     private void setHasDismissedQuickScrubOnboardingOnce(
             boolean hasDismissedQuickScrubOnboardingOnce) {
-        Log.d(TAG,
-                "setHasDismissedQuickScrubOnboardingOnce: " + hasDismissedQuickScrubOnboardingOnce);
         Prefs.putBoolean(mContext, HAS_DISMISSED_RECENTS_QUICK_SCRUB_ONBOARDING_ONCE,
                 hasDismissedQuickScrubOnboardingOnce);
     }
@@ -541,8 +534,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 +550,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/recents/ScreenPinningRequest.java b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
index 167df8c..481d54f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/ScreenPinningRequest.java
@@ -28,6 +28,7 @@
 import android.os.Binder;
 import android.os.RemoteException;
 import android.util.DisplayMetrics;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
@@ -40,6 +41,7 @@
 import android.widget.LinearLayout;
 import android.widget.TextView;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.R;
 import com.android.systemui.SysUiServiceProvider;
 import com.android.systemui.statusbar.phone.NavigationBarView;
@@ -259,10 +261,16 @@
             }
 
             if (navigationBarView != null) {
+                int dualToneDarkTheme = Utils.getThemeAttr(getContext(), R.attr.darkIconTheme);
+                int dualToneLightTheme = Utils.getThemeAttr(getContext(), R.attr.lightIconTheme);
+                Context lightContext = new ContextThemeWrapper(getContext(), dualToneLightTheme);
+                Context darkContext = new ContextThemeWrapper(getContext(), dualToneDarkTheme);
                 ((ImageView) mLayout.findViewById(R.id.screen_pinning_back_icon))
-                        .setImageDrawable(navigationBarView.getBackDrawable(mContext));
+                        .setImageDrawable(navigationBarView.getBackDrawable(lightContext,
+                                darkContext));
                 ((ImageView) mLayout.findViewById(R.id.screen_pinning_home_icon))
-                        .setImageDrawable(navigationBarView.getHomeDrawable(mContext));
+                        .setImageDrawable(navigationBarView.getHomeDrawable(lightContext,
+                                darkContext));
             }
 
             ((TextView) mLayout.findViewById(R.id.screen_pinning_description))
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/HeadsUpStatusBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
index 32e51b3..9f82bcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/HeadsUpStatusBarView.java
@@ -19,8 +19,10 @@
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.AttributeSet;
+import android.view.DisplayCutout;
 import android.view.View;
 import android.widget.TextView;
 
@@ -44,9 +46,10 @@
     private boolean mPublicMode;
     private int mMaxWidth;
     private View mRootView;
-    private int mLeftCutOutInset;
-    private int mLeftInset;
+    private int mSysWinInset;
+    private int mCutOutInset;
     private Rect mIconDrawingRect = new Rect();
+    private Point mPoint;
     private Runnable mOnDrawingRectChangedListener;
 
     public HeadsUpStatusBarView(Context context) {
@@ -137,9 +140,20 @@
         int bottom = top + mIconPlaceholder.getHeight();
         mLayoutedIconRect.set(left, top, right, bottom);
         updateDrawingRect();
-        int targetPadding = mAbsoluteStartPadding + mLeftInset + mLeftCutOutInset;
+        int targetPadding = mAbsoluteStartPadding + mSysWinInset + mCutOutInset;
         if (left != targetPadding) {
-            int newPadding = targetPadding - left + getPaddingStart();
+            int start;
+            if (isLayoutRtl()) {
+                if (mPoint == null) {
+                    mPoint = new Point();
+                }
+                getDisplay().getRealSize(mPoint);
+                start = (mPoint.x - right);
+            } else {
+                start = left;
+            }
+
+            int newPadding = targetPadding - start + getPaddingStart();
             setPaddingRelative(newPadding, 0, mEndMargin, 0);
         }
         if (mFirstLayout) {
@@ -152,7 +166,11 @@
     }
 
     public void setPanelTranslation(float translationX) {
-        setTranslationX(translationX - mLeftCutOutInset);
+        if (isLayoutRtl()) {
+            setTranslationX(translationX + mCutOutInset);
+        } else {
+            setTranslationX(translationX - mCutOutInset);
+        }
         updateDrawingRect();
     }
 
@@ -167,15 +185,19 @@
 
     @Override
     protected boolean fitSystemWindows(Rect insets) {
-        mLeftInset = insets.left;
-        mLeftCutOutInset = (getRootWindowInsets().getDisplayCutout() != null)
-                ? getRootWindowInsets().getDisplayCutout().getSafeInsetLeft() : 0;
-
+        boolean isRtl = isLayoutRtl();
+        mSysWinInset = isRtl ? insets.right : insets.left;
+        DisplayCutout displayCutout = getRootWindowInsets().getDisplayCutout();
+        mCutOutInset = (displayCutout != null)
+                ? (isRtl ? displayCutout.getSafeInsetRight() : displayCutout.getSafeInsetLeft())
+                : 0;
         // For Double Cut Out mode, the System window navigation bar is at the right
-        // hand side of the left cut out. In this condition, mLeftInset include the left cut
-        // out width so we set mLeftCutOutInset to be 0.
-        if (mLeftInset != 0) {
-            mLeftCutOutInset = 0;
+        // side of the left cut out. In this condition, mSysWinInset include the left cut
+        // out width so we set mCutOutInset to be 0. For RTL, the condition is the same.
+        // The navigation bar is at the left side of the right cut out and include the
+        // right cut out width.
+        if (mSysWinInset != 0) {
+            mCutOutInset = 0;
         }
 
         return super.fitSystemWindows(insets);
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/NotificationContentView.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
index 952c961..70dad19 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationContentView.java
@@ -189,6 +189,7 @@
             if (mExpandedSmartReplyView != null) {
                 notificationMaxHeight += mExpandedSmartReplyView.getHeightUpperLimit();
             }
+            notificationMaxHeight += mExpandedWrapper.getExtraMeasureHeight();
             int size = notificationMaxHeight;
             ViewGroup.LayoutParams layoutParams = mExpandedChild.getLayoutParams();
             boolean useExactly = false;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
index 419e262..e24d65a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationData.java
@@ -32,10 +32,13 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.NotificationManager;
+import android.app.Person;
 import android.content.Context;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.graphics.drawable.Icon;
+import android.os.Bundle;
+import android.os.Parcelable;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.service.notification.NotificationListenerService.Ranking;
@@ -50,6 +53,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.StatusBarIcon;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.Dependency;
 import com.android.systemui.ForegroundServiceController;
@@ -117,6 +121,11 @@
          */
         public Boolean mIsSystemNotification;
 
+        /**
+         * Has the user sent a reply through this Notification.
+         */
+        private boolean hasSentReply;
+
         public Entry(StatusBarNotification n) {
             this.key = n.getKey();
             this.notification = n;
@@ -298,6 +307,40 @@
             lastRemoteInputSent = NOT_LAUNCHED_YET;
             remoteInputTextWhenReset = null;
         }
+
+        public void setHasSentReply() {
+            hasSentReply = true;
+        }
+
+        public boolean isLastMessageFromReply() {
+            if (!hasSentReply) {
+                return false;
+            }
+            Bundle extras = notification.getNotification().extras;
+            CharSequence[] replyTexts = extras.getCharSequenceArray(
+                    Notification.EXTRA_REMOTE_INPUT_HISTORY);
+            if (!ArrayUtils.isEmpty(replyTexts)) {
+                return true;
+            }
+            Parcelable[] messages = extras.getParcelableArray(Notification.EXTRA_MESSAGES);
+            if (messages != null && messages.length > 0) {
+                Parcelable message = messages[messages.length - 1];
+                if (message instanceof Bundle) {
+                    Notification.MessagingStyle.Message lastMessage =
+                            Notification.MessagingStyle.Message.getMessageFromBundle(
+                                    (Bundle) message);
+                    if (lastMessage != null) {
+                        Person senderPerson = lastMessage.getSenderPerson();
+                        if (senderPerson == null) {
+                            return true;
+                        }
+                        Person user = extras.getParcelable(Notification.EXTRA_MESSAGING_PERSON);
+                        return Objects.equals(user, senderPerson);
+                    }
+                }
+            }
+            return false;
+        }
     }
 
     private final ArrayMap<String, Entry> mEntries = new ArrayMap<>();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
index 2b7ab10..e52829a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationInfo.java
@@ -300,9 +300,11 @@
 
     private void saveImportance() {
         if (!mIsNonblockable) {
-            // Only go through the lock screen/bouncer if the user didn't hit 'Keep showing'.
+            // Only go through the lock screen/bouncer if the user hit 'Stop notifications'.
+            // Otherwise, update the importance immediately.
             if (mCheckSaveListener != null
-                    && !NotificationCounters.BLOCKING_HELPER_KEEP_SHOWING.equals(mExitReason)) {
+                    && NotificationCounters.BLOCKING_HELPER_STOP_NOTIFICATIONS.equals(
+                            mExitReason)) {
                 mCheckSaveListener.checkSave(this::updateImportance, mSbn);
             } else {
                 updateImportance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
index 3cf59cf..257fa75 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/car/UserGridRecyclerView.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.statusbar.car;
 
+import static android.content.DialogInterface.BUTTON_NEGATIVE;
 import static android.content.DialogInterface.BUTTON_POSITIVE;
 
 import android.app.AlertDialog;
@@ -28,7 +29,6 @@
 import android.graphics.Bitmap;
 import android.os.AsyncTask;
 import android.os.UserHandle;
-import androidx.recyclerview.widget.RecyclerView;
 import android.util.AttributeSet;
 import android.view.LayoutInflater;
 import android.view.View;
@@ -37,9 +37,10 @@
 import android.widget.TextView;
 
 import androidx.car.widget.PagedListView;
-
 import androidx.core.graphics.drawable.RoundedBitmapDrawable;
 import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+import androidx.recyclerview.widget.RecyclerView;
+
 import com.android.internal.util.UserIcons;
 import com.android.settingslib.users.UserManagerHelper;
 import com.android.systemui.R;
@@ -166,6 +167,9 @@
         private AlertDialog mDialog;
         // View that holds the add user button.  Used to enable/disable the view
         private View mAddUserView;
+        // User record for the add user.  Need to call notifyUserSelected only if the user
+        // confirms adding a user
+        private UserRecord mAddUserRecord;
 
         public UserAdapter(Context context, List<UserRecord> users) {
             mRes = context.getResources();
@@ -200,18 +204,16 @@
             circleIcon.setCircular(true);
             holder.mUserAvatarImageView.setImageDrawable(circleIcon);
             holder.mUserNameTextView.setText(userRecord.mInfo.name);
+
             holder.mView.setOnClickListener(v -> {
                 if (userRecord == null) {
                     return;
                 }
 
-                // Notify the listener which user was selected
-                if (mUserSelectionListener != null) {
-                    mUserSelectionListener.onUserSelected(userRecord);
-                }
 
                 // If the user selects Guest, start the guest session.
                 if (userRecord.mIsStartGuestSession) {
+                    notifyUserSelected(userRecord);
                     mUserManagerHelper.startNewGuestSession(mGuestName);
                     return;
                 }
@@ -227,6 +229,7 @@
                         .concat(System.getProperty("line.separator"))
                         .concat(mRes.getString(R.string.user_add_user_message_update));
 
+                    mAddUserRecord = userRecord;
                     mDialog = new Builder(mContext, R.style.Theme_Car_Dark_Dialog_Alert)
                         .setTitle(R.string.user_add_user_title)
                         .setMessage(message)
@@ -239,11 +242,19 @@
                     return;
                 }
                 // If the user doesn't want to be a guest or add a user, switch to the user selected
+                notifyUserSelected(userRecord);
                 mUserManagerHelper.switchToUser(userRecord.mInfo);
             });
 
         }
 
+        private void notifyUserSelected(UserRecord userRecord) {
+            // Notify the listener which user was selected
+            if (mUserSelectionListener != null) {
+                mUserSelectionListener.onUserSelected(userRecord);
+            }
+        }
+
         private Bitmap getUserRecordIcon(UserRecord userRecord) {
             if (userRecord.mIsStartGuestSession) {
                 return mUserManagerHelper.getGuestDefaultIcon();
@@ -259,12 +270,14 @@
 
         @Override
         public void onClick(DialogInterface dialog, int which) {
-            // Enable the add button
-            if (mAddUserView != null) {
-                mAddUserView.setEnabled(true);
-            }
             if (which == BUTTON_POSITIVE) {
+                notifyUserSelected(mAddUserRecord);
                 new AddNewUserTask().execute(mNewUserName);
+            } else if (which == BUTTON_NEGATIVE) {
+                // Enable the add button only if cancel
+                if (mAddUserView != null) {
+                    mAddUserView.setEnabled(true);
+                }
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
index 2d983c4..91a4dda 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationTemplateViewWrapper.java
@@ -34,6 +34,7 @@
 import com.android.internal.util.NotificationColorUtil;
 import com.android.internal.widget.NotificationActionListLayout;
 import com.android.systemui.Dependency;
+import com.android.systemui.R;
 import com.android.systemui.UiOffloadThread;
 import com.android.systemui.statusbar.CrossFadeHelper;
 import com.android.systemui.statusbar.ExpandableNotificationRow;
@@ -58,6 +59,7 @@
     private NotificationActionListLayout mActions;
     private ArraySet<PendingIntent> mCancelledPendingIntents = new ArraySet<>();
     private UiOffloadThread mUiOffloadThread;
+    private View mRemoteInputHistory;
 
     protected NotificationTemplateViewWrapper(Context ctx, View view,
             ExpandableNotificationRow row) {
@@ -146,6 +148,8 @@
         mActionsContainer = mView.findViewById(com.android.internal.R.id.actions_container);
         mActions = mView.findViewById(com.android.internal.R.id.actions);
         mReplyAction = mView.findViewById(com.android.internal.R.id.reply_icon_action);
+        mRemoteInputHistory = mView.findViewById(
+                com.android.internal.R.id.notification_material_reply_container);
         updatePendingIntentCancellations();
     }
 
@@ -178,6 +182,9 @@
             }
         }
         if (mReplyAction != null) {
+            // Let's reset the view on update, assuming the new pending intent isn't cancelled
+            // anymore. The color filter automatically resets when it's updated.
+            mReplyAction.setEnabled(true);
             performOnPendingIntentCancellation(mReplyAction, () -> {
                 if (mReplyAction != null && mReplyAction.isEnabled()) {
                     mReplyAction.setEnabled(false);
@@ -329,6 +336,10 @@
         if (mActions != null) {
             extra = mActions.getExtraMeasureHeight();
         }
+        if (mRemoteInputHistory != null && mRemoteInputHistory.getVisibility() != View.GONE) {
+            extra += mRow.getContext().getResources().getDimensionPixelSize(
+                    R.dimen.remote_input_history_extra_height);
+        }
         return extra + super.getExtraMeasureHeight();
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
index 8ede224..879ac92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/TransformState.java
@@ -16,11 +16,8 @@
 
 package com.android.systemui.statusbar.notification;
 
-import android.util.ArraySet;
 import android.util.Pools;
 import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewParent;
 import android.view.animation.Interpolator;
 import android.widget.ImageView;
 import android.widget.ProgressBar;
@@ -411,7 +408,8 @@
         mOwnPosition[1] -= (1.0f - mTransformedView.getScaleY()) * mTransformedView.getPivotY();
 
         // Remove local translations
-        mOwnPosition[1] -= MessagingPropertyAnimator.getLocalTranslationY(mTransformedView);
+        mOwnPosition[1] -= MessagingPropertyAnimator.getTop(mTransformedView)
+                - MessagingPropertyAnimator.getLayoutTop(mTransformedView);
         return mOwnPosition;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
index 3c0b226..894ea62 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ButtonDispatcher.java
@@ -114,6 +114,10 @@
         return mVisibility != null ? mVisibility : View.VISIBLE;
     }
 
+    public boolean isVisible() {
+        return getVisibility() == View.VISIBLE;
+    }
+
     public float getAlpha() {
         return mAlpha != null ? mAlpha : 1;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
index 6d78d1d..b52e324 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/HeadsUpAppearanceController.java
@@ -16,8 +16,10 @@
 
 package com.android.systemui.statusbar.phone;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.view.View;
+import android.view.WindowInsets;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.systemui.Dependency;
@@ -59,6 +61,7 @@
     private final View.OnLayoutChangeListener mStackScrollLayoutChangeListener =
             (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
                     -> updatePanelTranslation();
+    Point mPoint;
 
     public HeadsUpAppearanceController(
             NotificationIconAreaController notificationIconAreaController,
@@ -121,8 +124,54 @@
         updateHeader(headsUp.getEntry());
     }
 
+    /** To count the distance from the window right boundary to scroller right boundary. The
+     * distance formula is the following:
+     *     Y = screenSize - (SystemWindow's width + Scroller.getRight())
+     * There are four modes MUST to be considered in Cut Out of RTL.
+     * No Cut Out:
+     *   Scroller + NB
+     *   NB + Scroller
+     *     => SystemWindow = NavigationBar's width
+     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+     * Corner Cut Out or Tall Cut Out:
+     *   cut out + Scroller + NB
+     *   NB + Scroller + cut out
+     *     => SystemWindow = NavigationBar's width
+     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+     * Double Cut Out:
+     *   cut out left + Scroller + (NB + cut out right)
+     *     SystemWindow = NavigationBar's width + cut out right width
+     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+     *   (cut out left + NB) + Scroller + cut out right
+     *     SystemWindow = NavigationBar's width + cut out left width
+     *     => Y = screenSize - (SystemWindow's width + Scroller.getRight())
+     * @return the translation X value for RTL. In theory, it should be negative. i.e. -Y
+     */
+    private int getRtlTranslation() {
+        // TODO: Corner Cut Out still need to handle.
+        if (mPoint == null) {
+            mPoint = new Point();
+        }
+
+        int realDisplaySize = 0;
+        if (mStackScroller.getDisplay() != null) {
+            mStackScroller.getDisplay().getRealSize(mPoint);
+            realDisplaySize = mPoint.x;
+        }
+
+        WindowInsets windowInset = mStackScroller.getRootWindowInsets();
+        return windowInset.getSystemWindowInsetLeft() + mStackScroller.getRight()
+                + windowInset.getSystemWindowInsetRight() - realDisplaySize;
+    }
+
     public void updatePanelTranslation() {
-        float newTranslation = mStackScroller.getLeft() + mStackScroller.getTranslationX();
+        float newTranslation;
+        if (mStackScroller.isLayoutRtl()) {
+            newTranslation = getRtlTranslation();
+        } else {
+            newTranslation = mStackScroller.getLeft();
+        }
+        newTranslation += mStackScroller.getTranslationX();
         mHeadsUpStatusBarView.setPanelTranslation(newTranslation);
     }
 
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 e2fec85..e096f3f 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 cfc8715..f9a540c 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 9261d2e..a3cba2d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -39,7 +39,6 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Message;
-import android.os.RemoteException;
 import android.os.SystemProperties;
 import androidx.annotation.ColorInt;
 import android.util.AttributeSet;
@@ -118,8 +117,9 @@
     private Rect mRecentsButtonBounds = new Rect();
     private Rect mRotationButtonBounds = new Rect();
     private int[] mTmpPosition = new int[2];
+    private Rect mTmpRect = new Rect();
 
-    private KeyButtonDrawable mBackIcon, mBackLandIcon, mBackAltIcon, mBackAltLandIcon;
+    private KeyButtonDrawable mBackIcon;
     private KeyButtonDrawable mBackCarModeIcon, mBackLandCarModeIcon;
     private KeyButtonDrawable mBackAltCarModeIcon, mBackAltLandCarModeIcon;
     private KeyButtonDrawable mHomeDefaultIcon, mHomeCarModeIcon;
@@ -336,13 +336,14 @@
                 int x = (int) event.getX();
                 int y = (int) event.getY();
                 mDownHitTarget = HIT_TARGET_NONE;
-                if (mBackButtonBounds.contains(x, y)) {
+                if (getBackButton().isVisible() && mBackButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_BACK;
-                } else if (mHomeButtonBounds.contains(x, y)) {
+                } else if (getHomeButton().isVisible() && mHomeButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_HOME;
-                } else if (mRecentsButtonBounds.contains(x, y)) {
+                } else if (getRecentsButton().isVisible() && mRecentsButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_OVERVIEW;
-                } else if (mRotationButtonBounds.contains(x, y)) {
+                } else if (getRotateSuggestionButton().isVisible()
+                        && mRotationButtonBounds.contains(x, y)) {
                     mDownHitTarget = HIT_TARGET_ROTATION;
                 }
                 break;
@@ -453,6 +454,7 @@
                 && ((mOverviewProxyService.getInteractionFlags() & FLAG_DISABLE_QUICK_SCRUB) == 0);
     }
 
+    // TODO(b/80003212): change car mode icons to vector icons.
     private void updateCarModeIcons(Context ctx) {
         mBackCarModeIcon = getDrawable(ctx,
                 R.drawable.ic_sysbar_back_carmode, R.drawable.ic_sysbar_back_carmode);
@@ -469,33 +471,27 @@
     }
 
     private void updateIcons(Context ctx, Configuration oldConfig, Configuration newConfig) {
+        int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+        int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+        Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
+        Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+
         if (oldConfig.orientation != newConfig.orientation
                 || oldConfig.densityDpi != newConfig.densityDpi) {
-            mDockedIcon = getDrawable(ctx,
-                    R.drawable.ic_sysbar_docked, R.drawable.ic_sysbar_docked_dark);
-            mHomeDefaultIcon = getHomeDrawable(ctx);
+            mDockedIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_docked);
+            mHomeDefaultIcon = getHomeDrawable(lightContext, darkContext);
         }
         if (oldConfig.densityDpi != newConfig.densityDpi
                 || oldConfig.getLayoutDirection() != newConfig.getLayoutDirection()) {
-            mBackIcon = getBackDrawable(ctx);
-            mBackLandIcon = mBackIcon;
-            mBackAltIcon = getBackImeDrawable(ctx);
-            mBackAltLandIcon = mBackAltIcon;
-            mRecentIcon = getDrawable(ctx,
-                    R.drawable.ic_sysbar_recent, R.drawable.ic_sysbar_recent_dark);
-            mMenuIcon = getDrawable(ctx, R.drawable.ic_sysbar_menu, R.drawable.ic_sysbar_menu_dark);
+            mBackIcon = getBackDrawable(lightContext, darkContext);
+            mRecentIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_recent);
+            mMenuIcon = getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_menu);
 
-            int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
-            int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
-            Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
-            Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
+            mAccessibilityIcon = getDrawable(lightContext, darkContext,
+                    R.drawable.ic_sysbar_accessibility_button, false /* hasShadow */);
 
-            mAccessibilityIcon = getDrawable(darkContext, lightContext,
-                    R.drawable.ic_sysbar_accessibility_button,
-                    R.drawable.ic_sysbar_accessibility_button);
-
-            mImeIcon = getDrawable(darkContext, lightContext,
-                    R.drawable.ic_ime_switcher_default, R.drawable.ic_ime_switcher_default);
+            mImeIcon = getDrawable(lightContext, darkContext, R.drawable.ic_ime_switcher_default,
+                    false /* hasShadow */);
 
             updateRotateSuggestionButtonStyle(mRotateBtnStyle, false);
 
@@ -505,42 +501,58 @@
         }
     }
 
-    public KeyButtonDrawable getBackDrawable(Context ctx) {
-        return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back,
-                R.drawable.ic_sysbar_back_dark, R.drawable.ic_sysbar_back_quick_step,
-                R.drawable.ic_sysbar_back_quick_step_dark);
+    public KeyButtonDrawable getBackDrawable(Context lightContext, Context darkContext) {
+        KeyButtonDrawable drawable = chooseNavigationIconDrawable(lightContext, darkContext,
+                R.drawable.ic_sysbar_back, R.drawable.ic_sysbar_back_quick_step);
+        orientBackButton(drawable);
+        return drawable;
     }
 
-    public KeyButtonDrawable getBackImeDrawable(Context ctx) {
-        return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_back_ime,
-                R.drawable.ic_sysbar_back_ime_dark, R.drawable.ic_sysbar_back_ime_quick_step,
-                R.drawable.ic_sysbar_back_ime_quick_step_dark);
+    public KeyButtonDrawable getHomeDrawable(Context lightContext, Context darkContext) {
+        final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
+        KeyButtonDrawable drawable = quickStepEnabled
+                ? getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_home_quick_step)
+                : getDrawable(lightContext, darkContext, R.drawable.ic_sysbar_home,
+                        false /* hasShadow */);
+        orientHomeButton(drawable);
+        return drawable;
     }
 
-    public KeyButtonDrawable getHomeDrawable(Context ctx) {
-        return chooseNavigationIconDrawable(ctx, R.drawable.ic_sysbar_home,
-                R.drawable.ic_sysbar_home_dark, R.drawable.ic_sysbar_home_quick_step,
-                R.drawable.ic_sysbar_home_quick_step_dark);
+    private void orientBackButton(KeyButtonDrawable drawable) {
+        final boolean useAltBack =
+            (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+        drawable.setRotation(useAltBack
+                ? -90 : (getLayoutDirection() == View.LAYOUT_DIRECTION_RTL) ? 180 : 0);
     }
 
-    private KeyButtonDrawable chooseNavigationIconDrawable(Context ctx, @DrawableRes int iconLight,
-            @DrawableRes int iconDark, @DrawableRes int quickStepIconLight,
-            @DrawableRes int quickStepIconDark) {
+    private void orientHomeButton(KeyButtonDrawable drawable) {
+        drawable.setRotation(mVertical ? 90 : 0);
+    }
+
+    private KeyButtonDrawable chooseNavigationIconDrawable(Context lightContext,
+            Context darkContext, @DrawableRes int icon, @DrawableRes int quickStepIcon) {
         final boolean quickStepEnabled = mOverviewProxyService.shouldShowSwipeUpUI();
         return quickStepEnabled
-                ? getDrawable(ctx, quickStepIconLight, quickStepIconDark)
-                : getDrawable(ctx, iconLight, iconDark);
+                ? getDrawable(lightContext, darkContext, quickStepIcon)
+                : getDrawable(lightContext, darkContext, icon);
+    }
+
+    private KeyButtonDrawable getDrawable(Context lightContext, Context darkContext,
+            @DrawableRes int icon) {
+        return getDrawable(lightContext, darkContext, icon, true /* hasShadow */);
+    }
+
+    private KeyButtonDrawable getDrawable(Context lightContext, Context darkContext,
+            @DrawableRes int icon, boolean hasShadow) {
+        return KeyButtonDrawable.create(lightContext, lightContext.getDrawable(icon),
+                darkContext.getDrawable(icon), hasShadow);
     }
 
     private KeyButtonDrawable getDrawable(Context ctx, @DrawableRes int lightIcon,
             @DrawableRes int darkIcon) {
-        return getDrawable(ctx, ctx, lightIcon, darkIcon);
-    }
-
-    private KeyButtonDrawable getDrawable(Context darkContext, Context lightContext,
-            @DrawableRes int lightIcon, @DrawableRes int darkIcon) {
-        return KeyButtonDrawable.create(lightContext.getDrawable(lightIcon),
-                darkContext.getDrawable(darkIcon));
+        // Legacy image icons using separate light and dark images will not support shadows
+        return KeyButtonDrawable.create(ctx, ctx.getDrawable(lightIcon),
+            ctx.getDrawable(darkIcon), false /* hasShadow */);
     }
 
     private TintedKeyButtonDrawable getDrawable(Context ctx, @DrawableRes int icon,
@@ -557,13 +569,13 @@
 
     private KeyButtonDrawable getBackIconWithAlt(boolean carMode, boolean landscape) {
         return landscape
-                ? carMode ? mBackAltLandCarModeIcon : mBackAltLandIcon
-                : carMode ? mBackAltCarModeIcon : mBackAltIcon;
+                ? carMode ? mBackAltLandCarModeIcon : mBackIcon
+                : carMode ? mBackAltCarModeIcon : mBackIcon;
     }
 
     private KeyButtonDrawable getBackIcon(boolean carMode, boolean landscape) {
         return landscape
-                ? carMode ? mBackLandCarModeIcon : mBackLandIcon
+                ? carMode ? mBackLandCarModeIcon : mBackIcon
                 : carMode ? mBackCarModeIcon : mBackIcon;
     }
 
@@ -594,26 +606,28 @@
         }
 
         updateNavButtonIcons();
+        updateSlippery();
     }
 
     public void updateNavButtonIcons() {
         // We have to replace or restore the back and home button icons when exiting or entering
         // carmode, respectively. Recents are not available in CarMode in nav bar so change
         // to recent icon is not required.
-        KeyButtonDrawable backIcon
-                = ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0)
-                        ? getBackIconWithAlt(mUseCarModeUi, mVertical)
-                        : getBackIcon(mUseCarModeUi, mVertical);
+        final boolean useAltBack =
+                (mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) != 0;
+        KeyButtonDrawable backIcon = useAltBack
+                ? getBackIconWithAlt(mUseCarModeUi, mVertical)
+                : getBackIcon(mUseCarModeUi, mVertical);
+        KeyButtonDrawable homeIcon = mUseCarModeUi ? mHomeCarModeIcon : mHomeDefaultIcon;
+        if (!mUseCarModeUi) {
+            orientBackButton(backIcon);
+            orientHomeButton(homeIcon);
+        }
+        getHomeButton().setImageDrawable(homeIcon);
         getBackButton().setImageDrawable(backIcon);
 
         updateRecentsIcon();
 
-        if (mUseCarModeUi) {
-            getHomeButton().setImageDrawable(mHomeCarModeIcon);
-        } else {
-            getHomeButton().setImageDrawable(mHomeDefaultIcon);
-        }
-
         // Update IME button visibility, a11y and rotate button always overrides the appearance
         final boolean showImeButton =
                 !mShowAccessibilityButton &&
@@ -640,8 +654,7 @@
         // Always disable recents when alternate car mode UI is active.
         boolean disableRecent = mUseCarModeUi || !isOverviewEnabled();
 
-        boolean disableBack = ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0)
-                && ((mNavigationIconHints & StatusBarManager.NAVIGATION_HINT_BACK_ALT) == 0);
+        boolean disableBack = ((mDisabledFlags & View.STATUS_BAR_DISABLE_BACK) != 0) && !useAltBack;
 
         // When screen pinning, don't hide back and home when connected service or back and
         // recents buttons when disconnected from launcher service in screen pinning mode,
@@ -735,6 +748,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();
@@ -859,14 +878,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);
@@ -945,6 +977,7 @@
     }
 
     private void updateRecentsIcon() {
+        mDockedIcon.setRotation(mDockedStackExists && mVertical ? 90 : 0);
         getRecentsButton().setImageDrawable(mDockedStackExists ? mDockedIcon : mRecentIcon);
         mBarTransitions.reapplyDarkIntensity();
     }
@@ -1158,10 +1191,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/NotificationIconAreaController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
index 2be10e8..a78dd25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconAreaController.java
@@ -141,7 +141,7 @@
     }
 
     protected boolean shouldShowNotificationIcon(NotificationData.Entry entry,
-            boolean showAmbient, boolean hideDismissed) {
+            boolean showAmbient, boolean hideDismissed, boolean hideRepliedMessages) {
         if (mEntryManager.getNotificationData().isAmbient(entry.key) && !showAmbient) {
             return false;
         }
@@ -155,6 +155,10 @@
             return false;
         }
 
+        if (hideRepliedMessages && entry.isLastMessageFromReply()) {
+            return false;
+        }
+
         // showAmbient == show in shade but not shelf
         if (!showAmbient && mEntryManager.getNotificationData().shouldSuppressStatusBar(entry)) {
             return false;
@@ -170,14 +174,15 @@
 
         updateStatusBarIcons();
         updateIconsForLayout(entry -> entry.expandedIcon, mShelfIcons,
-                NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */);
+                NotificationShelf.SHOW_AMBIENT_ICONS, false /* hideDismissed */,
+                false /* hideRepliedMessages */);
 
         applyNotificationIconsTint();
     }
 
-    private void updateStatusBarIcons() {
+    public void updateStatusBarIcons() {
         updateIconsForLayout(entry -> entry.icon, mNotificationIcons,
-                false /* showAmbient */, true /* hideDismissed */);
+                false /* showAmbient */, true /* hideDismissed */, true /* hideRepliedMessages */);
     }
 
     /**
@@ -187,9 +192,11 @@
      * @param hostLayout which layout should be updated
      * @param showAmbient should ambient notification icons be shown
      * @param hideDismissed should dismissed icons be hidden
+     * @param hideRepliedMessages should messages that have been replied to be hidden
      */
     private void updateIconsForLayout(Function<NotificationData.Entry, StatusBarIconView> function,
-            NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed) {
+            NotificationIconContainer hostLayout, boolean showAmbient, boolean hideDismissed,
+            boolean hideRepliedMessages) {
         ArrayList<StatusBarIconView> toShow = new ArrayList<>(
                 mNotificationScrollLayout.getChildCount());
 
@@ -198,7 +205,8 @@
             View view = mNotificationScrollLayout.getChildAt(i);
             if (view instanceof ExpandableNotificationRow) {
                 NotificationData.Entry ent = ((ExpandableNotificationRow) view).getEntry();
-                if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed)) {
+                if (shouldShowNotificationIcon(ent, showAmbient, hideDismissed,
+                        hideRepliedMessages)) {
                     toShow.add(function.apply(ent));
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
index 2ec9312..653471d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NotificationIconContainer.java
@@ -129,13 +129,14 @@
 
     public static final int MAX_VISIBLE_ICONS_WHEN_DARK = 5;
     public static final int MAX_STATIC_ICONS = 4;
-    private static final int MAX_DOTS = 3;
+    private static final int MAX_DOTS = 1;
 
     private boolean mIsStaticLayout = true;
     private final HashMap<View, IconState> mIconStates = new HashMap<>();
     private int mDotPadding;
     private int mStaticDotRadius;
     private int mStaticDotDiameter;
+    private int mOverflowWidth;
     private int mActualLayoutWidth = NO_VALUE;
     private float mActualPaddingEnd = NO_VALUE;
     private float mActualPaddingStart = NO_VALUE;
@@ -230,7 +231,7 @@
             int top = (int) (centerY - height / 2.0f);
             child.layout(0, top, width, top + height);
             if (i == 0) {
-                mIconSize = child.getWidth();
+                setIconSize(child.getWidth());
             }
         }
         getLocationOnScreen(mAbsolutePosition);
@@ -239,6 +240,11 @@
         }
     }
 
+    private void setIconSize(int size) {
+        mIconSize = size;
+        mOverflowWidth = mIconSize + (MAX_DOTS - 1) * (mStaticDotDiameter + mDotPadding);
+    }
+
     private void updateState() {
         resetViewStates();
         calculateIconTranslations();
@@ -391,12 +397,12 @@
             iconState.visibleState = StatusBarIconView.STATE_ICON;
 
             boolean isOverflowing =
-                    (translationX >= (noOverflowAfter ? layoutEnd - mIconSize : overflowStart));
+                    (translationX > (noOverflowAfter ? layoutEnd - mIconSize
+                            : overflowStart - mIconSize));
             if (firstOverflowIndex == -1 && (forceOverflow || isOverflowing)) {
                 firstOverflowIndex = noOverflowAfter && !forceOverflow ? i - 1 : i;
-                mVisualOverflowStart = layoutEnd - mIconSize
-                        - 2 * (mStaticDotDiameter + mDotPadding);
-                if (forceOverflow) {
+                mVisualOverflowStart = layoutEnd - mOverflowWidth;
+                if (forceOverflow || mIsStaticLayout) {
                     mVisualOverflowStart = Math.min(translationX, mVisualOverflowStart);
                 }
             }
@@ -408,7 +414,7 @@
             for (int i = firstOverflowIndex; i < childCount; i++) {
                 View view = getChildAt(i);
                 IconState iconState = mIconStates.get(view);
-                int dotWidth = mStaticDotRadius * 2 + mDotPadding;
+                int dotWidth = mStaticDotDiameter + mDotPadding;
                 iconState.xTranslation = translationX;
                 if (mNumDots < MAX_DOTS) {
                     if (mNumDots == 0 && iconState.iconAppearAmount < 0.8f) {
@@ -536,7 +542,7 @@
     }
 
     private float getMaxOverflowStart() {
-        return getLayoutEnd() - mIconSize * (2 + OVERFLOW_EARLY_AMOUNT);
+        return getLayoutEnd() - mOverflowWidth;
     }
 
     public void setChangingViewPositions(boolean changingViewPositions) {
@@ -607,7 +613,7 @@
             return 0;
         }
 
-        int collapsedPadding = mIconSize + 2 * (mStaticDotDiameter + mDotPadding);
+        int collapsedPadding = mOverflowWidth;
 
         if (collapsedPadding + getFinalTranslationX() > getWidth()) {
             collapsedPadding = getWidth() - getFinalTranslationX();
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 20852ff..ea1b980 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,29 @@
 
 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.ValueAnimator;
-import android.animation.ValueAnimator.AnimatorUpdateListener;
+import android.animation.PropertyValuesHolder;
 import android.content.Context;
+import android.content.res.Resources;
 import android.graphics.Canvas;
+import android.graphics.Color;
 import android.graphics.Matrix;
-import android.graphics.Paint;
 import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
 import android.os.Handler;
 import android.os.RemoteException;
+import android.util.FloatProperty;
 import android.util.Log;
 import android.util.Slog;
 import android.view.MotionEvent;
@@ -45,12 +54,7 @@
 import com.android.systemui.shared.recents.IOverviewProxy;
 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;
+import com.android.internal.graphics.ColorUtils;
 
 /**
  * Class to detect gestures on the navigation bar and implement quick scrub.
@@ -58,88 +62,100 @@
 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 = 134;
+    private static final float TRACK_SCALE = 0.95f;
 
     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;
     private float mTrackAlpha;
+    private float mTrackScale = TRACK_SCALE;
     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 Drawable mTrackDrawable;
     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> mTrackScaleProperty =
+            new FloatProperty<QuickStepController>("TrackScale") {
+        @Override
+        public void setValue(QuickStepController controller, float scale) {
+            mTrackScale = scale;
+            mNavigationBarView.invalidate();
         }
-        if (mIsVertical) {
-            mHomeButtonView.setTranslationY(pos);
-        } else {
-            mHomeButtonView.setTranslationX(pos);
+
+        @Override
+        public Float get(QuickStepController controller) {
+            return mTrackScale;
+        }
+    };
+
+    private final FloatProperty<QuickStepController> mNavBarAlphaProperty =
+            new FloatProperty<QuickStepController>("NavBarAlpha") {
+        @Override
+        public void setValue(QuickStepController controller, float alpha) {
+            if (mCurrentNavigationBarView != null) {
+                mCurrentNavigationBarView.setAlpha(alpha);
+            }
+        }
+
+        @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);
-        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);
+        mTrackThickness = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_thickness);
+        mTrackEndPadding = res.getDimensionPixelSize(R.dimen.nav_quick_scrub_track_edge_padding);
+        mTrackDrawable = context.getDrawable(R.drawable.qs_scrubber_track).mutate();
     }
 
     public void setComponents(NavigationBarView navigationBarView) {
@@ -170,24 +186,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 +219,7 @@
                 break;
             }
             case MotionEvent.ACTION_MOVE: {
-                if (mQuickStepStarted || !mAllowGestureDetection || mHomeButtonView == null){
+                if (mQuickStepStarted || !mAllowGestureDetection){
                     break;
                 }
                 int x = (int) event.getX();
@@ -207,7 +227,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 +235,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 +244,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 +258,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 +269,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;
@@ -314,30 +312,41 @@
         }
         int color = (int) mTrackColorEvaluator.evaluate(mDarkIntensity, mLightTrackColor,
                 mDarkTrackColor);
-        mTrackPaint.setColor(color);
-        mTrackPaint.setAlpha((int) (mTrackPaint.getAlpha() * mTrackAlpha));
-        canvas.drawRect(mTrackRect, mTrackPaint);
+        int colorAlpha = ColorUtils.setAlphaComponent(color,
+                (int) (Color.alpha(color) * mTrackAlpha));
+        mTrackDrawable.setTint(colorAlpha);
+
+        // Scale the track, but apply the inverse scale from the nav bar
+        canvas.save();
+        canvas.scale(mTrackScale / mNavigationBarView.getScaleX(),
+                1f / mNavigationBarView.getScaleY(),
+                mTrackRect.centerX(), mTrackRect.centerY());
+        mTrackDrawable.draw(canvas);
+        canvas.restore();
     }
 
     @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);
+        mTrackDrawable.setBounds(mTrackRect);
     }
 
     @Override
@@ -386,24 +395,34 @@
             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.ofPropertyValuesHolder(this,
+                    PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 1f),
+                    PropertyValuesHolder.ofFloat(mTrackScaleProperty, 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 +433,58 @@
                 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.ofPropertyValuesHolder(this,
+                PropertyValuesHolder.ofFloat(mTrackAlphaProperty, 0f),
+                PropertyValuesHolder.ofFloat(mTrackScaleProperty, TRACK_SCALE));
+        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 +504,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/ShadowKeyDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadowKeyDrawable.java
new file mode 100644
index 0000000..8311dfd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ShadowKeyDrawable.java
@@ -0,0 +1,207 @@
+/*
+ * 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
+ */
+
+package com.android.systemui.statusbar.phone;
+
+
+import android.graphics.Bitmap;
+import android.graphics.BlurMaskFilter;
+import android.graphics.BlurMaskFilter.Blur;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorFilter;
+import android.graphics.Paint;
+import android.graphics.PixelFormat;
+import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
+
+import com.android.systemui.R;
+
+/**
+ * A drawable which adds shadow around a child drawable.
+ */
+public class ShadowKeyDrawable extends Drawable {
+    private final Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+
+    private final ShadowDrawableState mState;
+
+    public ShadowKeyDrawable(Drawable d) {
+        this(d, new ShadowDrawableState());
+    }
+
+    private ShadowKeyDrawable(Drawable d, ShadowDrawableState state) {
+        mState = state;
+        if (d != null) {
+            mState.mBaseHeight = d.getIntrinsicHeight();
+            mState.mBaseWidth = d.getIntrinsicWidth();
+            mState.mChangingConfigurations = d.getChangingConfigurations();
+            mState.mChildState = d.getConstantState();
+        }
+    }
+
+    public void setRotation(float degrees) {
+        if (mState.mRotateDegrees != degrees) {
+            mState.mRotateDegrees = degrees;
+            mState.mLastDrawnBitmap = null;
+            invalidateSelf();
+        }
+    }
+
+    public void setShadowProperties(int x, int y, int size, int color) {
+        if (mState.mShadowOffsetX != x || mState.mShadowOffsetY != y
+                || mState.mShadowSize != size || mState.mShadowColor != color) {
+            mState.mShadowOffsetX = x;
+            mState.mShadowOffsetY = y;
+            mState.mShadowSize = size;
+            mState.mShadowColor = color;
+            mState.mLastDrawnBitmap = null;
+            invalidateSelf();
+        }
+    }
+
+    public float getRotation() {
+        return mState.mRotateDegrees;
+    }
+
+    @Override
+    public void draw(Canvas canvas) {
+        Rect bounds = getBounds();
+        if (bounds.isEmpty()) {
+            return;
+        }
+        if (mState.mLastDrawnBitmap == null) {
+            regenerateBitmapCache();
+        }
+        canvas.drawBitmap(mState.mLastDrawnBitmap, null, bounds, mPaint);
+    }
+
+    @Override
+    public void setTint(int tintColor) {
+        super.setTint(tintColor);
+    }
+
+    @Override
+    public void setAlpha(int alpha) {
+        mPaint.setAlpha(alpha);
+        invalidateSelf();
+    }
+
+    @Override
+    public void setColorFilter(ColorFilter colorFilter) {
+        mPaint.setColorFilter(colorFilter);
+        invalidateSelf();
+    }
+
+    @Override
+    public ConstantState getConstantState() {
+        return mState;
+    }
+
+    @Override
+    public int getOpacity() {
+        return PixelFormat.TRANSLUCENT;
+    }
+
+    @Override
+    public int getIntrinsicHeight() {
+        return mState.mBaseHeight;
+    }
+
+    @Override
+    public int getIntrinsicWidth() {
+        return mState.mBaseWidth;
+    }
+
+    @Override
+    public boolean canApplyTheme() {
+        return mState.canApplyTheme();
+    }
+
+    private void regenerateBitmapCache() {
+        final int width = getIntrinsicWidth();
+        final int height = getIntrinsicHeight();
+        Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
+        Canvas canvas = new Canvas(bitmap);
+        canvas.save();
+        final float radians = (float) (mState.mRotateDegrees * Math.PI / 180);
+
+        // Rotate canvas before drawing original drawable if no shadow
+        if (mState.mShadowSize == 0) {
+            canvas.rotate(mState.mRotateDegrees, width / 2, height / 2);
+        }
+
+        // Call mutate, so that the pixel allocation by the underlying vector drawable is cleared.
+        final Drawable d = mState.mChildState.newDrawable().mutate();
+        d.setBounds(0, 0, mState.mBaseWidth, mState.mBaseHeight);
+        d.draw(canvas);
+
+        if (mState.mShadowSize > 0) {
+            // Draws the shadow
+            Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
+            paint.setMaskFilter(new BlurMaskFilter(mState.mShadowSize, Blur.NORMAL));
+            int[] offset = new int[2];
+
+            final Bitmap shadow = bitmap.extractAlpha(paint, offset);
+
+            paint.setMaskFilter(null);
+            paint.setColor(mState.mShadowColor);
+            bitmap.eraseColor(Color.TRANSPARENT);
+
+            canvas.rotate(mState.mRotateDegrees, width / 2, height / 2);
+
+            final float shadowOffsetX = (float) (Math.sin(radians) * mState.mShadowOffsetY
+                    + Math.cos(radians) * mState.mShadowOffsetX);
+            final float shadowOffsetY = (float) (Math.cos(radians) * mState.mShadowOffsetY
+                    - Math.sin(radians) * mState.mShadowOffsetX);
+
+            canvas.drawBitmap(shadow, offset[0] + shadowOffsetX, offset[1] + shadowOffsetY, paint);
+            d.draw(canvas);
+        }
+
+        bitmap = bitmap.copy(Bitmap.Config.HARDWARE, false);
+        mState.mLastDrawnBitmap = bitmap;
+        canvas.restore();
+    }
+
+    private static class ShadowDrawableState extends ConstantState {
+        int mChangingConfigurations;
+        int mBaseWidth;
+        int mBaseHeight;
+        float mRotateDegrees;
+        int mShadowOffsetX;
+        int mShadowOffsetY;
+        int mShadowSize;
+        int mShadowColor;
+
+        Bitmap mLastDrawnBitmap;
+        ConstantState mChildState;
+
+        @Override
+        public Drawable newDrawable() {
+            return new ShadowKeyDrawable(null, this);
+        }
+
+        @Override
+        public int getChangingConfigurations() {
+            return mChangingConfigurations;
+        }
+
+        @Override
+        public boolean canApplyTheme() {
+            return true;
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index 1b658b8..c70f034 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -234,6 +234,7 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.OnHeadsUpChangedListener;
 import com.android.systemui.statusbar.policy.PreviewInflater;
+import com.android.systemui.statusbar.policy.RemoteInputQuickSettingsDisabler;
 import com.android.systemui.statusbar.policy.UserInfoController;
 import com.android.systemui.statusbar.policy.UserInfoControllerImpl;
 import com.android.systemui.statusbar.policy.UserSwitcherController;
@@ -399,6 +400,9 @@
     private View mPendingRemoteInputView;
     private View mPendingWorkRemoteInputView;
 
+    private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler =
+            Dependency.get(RemoteInputQuickSettingsDisabler.class);
+
     private View mReportRejectedTouch;
 
     private int mMaxAllowedKeyguardNotifications;
@@ -1759,6 +1763,8 @@
      */
     @Override
     public void disable(int state1, int state2, boolean animate) {
+        state2 = mRemoteInputQuickSettingsDisabler.adjustDisableFlags(state2);
+
         animate &= mStatusBarWindowState != WINDOW_STATE_HIDDEN;
         final int old1 = mDisabled1;
         final int diff1 = state1 ^ old1;
@@ -2090,7 +2096,8 @@
      * @param animate should the change of the icons be animated.
      */
     private void updateHideIconsForBouncer(boolean animate) {
-        boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded && mStatusBarWindowHidden;
+        boolean hideBecauseApp = mTopHidesStatusBar && mIsOccluded
+                && (mStatusBarWindowHidden || mBouncerShowing);
         boolean hideBecauseKeyguard = !mPanelExpanded && !mIsOccluded && mBouncerShowing;
         boolean shouldHideIconsForBouncer = hideBecauseApp || hideBecauseKeyguard;
         if (mHideIconsForBouncer != shouldHideIconsForBouncer) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index 4bda017..fe86378 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -174,11 +174,13 @@
                 || mStatusBar.isFullScreenUserSwitcherState()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
         } else if (mShowing && !mDozing) {
-            mBouncer.setExpansion(expansion);
+            if (!isWakeAndUnlocking()) {
+                mBouncer.setExpansion(expansion);
+            }
             if (expansion != KeyguardBouncer.EXPANSION_HIDDEN && tracking
                     && mStatusBar.isKeyguardCurrentlySecure()
                     && !mBouncer.isShowing() && !mBouncer.isAnimatingAway()) {
-                mBouncer.show(false /* resetSecuritySelection */, false /* animated */);
+                mBouncer.show(false /* resetSecuritySelection */, false /* scrimmed */);
             }
         }
     }
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/FlashlightControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
index f0cfa2c..11fc408 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/FlashlightControllerImpl.java
@@ -17,6 +17,7 @@
 package com.android.systemui.statusbar.policy;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.hardware.camera2.CameraAccessException;
 import android.hardware.camera2.CameraCharacteristics;
@@ -24,6 +25,8 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Process;
+import android.provider.Settings;
+import android.provider.Settings.Secure;
 import android.text.TextUtils;
 import android.util.Log;
 
@@ -46,6 +49,9 @@
     private static final int DISPATCH_CHANGED = 1;
     private static final int DISPATCH_AVAILABILITY_CHANGED = 2;
 
+    private static final String ACTION_FLASHLIGHT_CHANGED =
+        "com.android.settings.flashlight.action.FLASHLIGHT_CHANGED";
+
     private final CameraManager mCameraManager;
     private final Context mContext;
     /** Call {@link #ensureHandler()} before using */
@@ -206,6 +212,9 @@
         public void onTorchModeUnavailable(String cameraId) {
             if (TextUtils.equals(cameraId, mCameraId)) {
                 setCameraAvailable(false);
+                Settings.Secure.putInt(
+                    mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 0);
+
             }
         }
 
@@ -214,6 +223,11 @@
             if (TextUtils.equals(cameraId, mCameraId)) {
                 setCameraAvailable(true);
                 setTorchMode(enabled);
+                Settings.Secure.putInt(
+                    mContext.getContentResolver(), Settings.Secure.FLASHLIGHT_AVAILABLE, 1);
+                Settings.Secure.putInt(
+                    mContext.getContentResolver(), Secure.FLASHLIGHT_ENABLED, enabled ? 1 : 0);
+                mContext.sendBroadcast(new Intent(ACTION_FLASHLIGHT_CHANGED));
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
index cce9d1c..1a85c47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyButtonDrawable.java
@@ -17,10 +17,16 @@
 package com.android.systemui.statusbar.policy;
 
 import android.annotation.Nullable;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Color;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.LayerDrawable;
 import android.view.Gravity;
 
+import com.android.systemui.R;
+import com.android.systemui.statusbar.phone.ShadowKeyDrawable;
+
 /**
  * Drawable for {@link KeyButtonView}s which contains an asset for both normal mode and light
  * navigation bar mode.
@@ -29,13 +35,24 @@
 
     private final boolean mHasDarkDrawable;
 
-    public static KeyButtonDrawable create(Drawable lightDrawable,
-            @Nullable Drawable darkDrawable) {
+    public static KeyButtonDrawable create(Context lightContext, Drawable lightDrawable,
+            @Nullable Drawable darkDrawable, boolean hasShadow) {
         if (darkDrawable != null) {
-            return new KeyButtonDrawable(
-                    new Drawable[] { lightDrawable.mutate(), darkDrawable.mutate() });
+            ShadowKeyDrawable light = new ShadowKeyDrawable(lightDrawable.mutate());
+            ShadowKeyDrawable dark = new ShadowKeyDrawable(darkDrawable.mutate());
+            if (hasShadow) {
+                // Only apply the shadow on the light drawable
+                Resources res = lightContext.getResources();
+                int offsetX = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_x);
+                int offsetY = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_offset_y);
+                int radius = res.getDimensionPixelSize(R.dimen.nav_key_button_shadow_radius);
+                int color = lightContext.getColor(R.color.nav_key_button_shadow_color);
+                light.setShadowProperties(offsetX, offsetY, radius, color);
+            }
+            return new KeyButtonDrawable(new Drawable[] { light, dark });
         } else {
-            return new KeyButtonDrawable(new Drawable[] { lightDrawable.mutate() });
+            return new KeyButtonDrawable(new Drawable[] {
+                    new ShadowKeyDrawable(lightDrawable.mutate()) });
         }
     }
 
@@ -57,4 +74,13 @@
         getDrawable(1).setAlpha((int) (intensity * 255f));
         invalidateSelf();
     }
+
+    public void setRotation(float degrees) {
+        if (getDrawable(0) instanceof ShadowKeyDrawable) {
+            ((ShadowKeyDrawable) getDrawable(0)).setRotation(degrees);
+        }
+        if (mHasDarkDrawable && getDrawable(1) instanceof ShadowKeyDrawable) {
+            ((ShadowKeyDrawable) getDrawable(1)).setRotation(degrees);
+        }
+    }
 }
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/policy/RemoteInputQuickSettingsDisabler.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
new file mode 100644
index 0000000..c2933e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisabler.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import android.app.StatusBarManager;
+import android.content.Context;
+import android.content.res.Configuration;
+
+import com.android.internal.annotations.VisibleForTesting;
+import com.android.systemui.Dependency;
+import com.android.systemui.SysUiServiceProvider;
+import com.android.systemui.qs.QSFragment;
+import com.android.systemui.statusbar.CommandQueue;
+import com.android.systemui.statusbar.phone.StatusBar;
+
+/**
+ * Let {@link RemoteInputView} to control the visibility of QuickSetting.
+ */
+public class RemoteInputQuickSettingsDisabler
+        implements ConfigurationController.ConfigurationListener {
+
+    private Context mContext;
+    @VisibleForTesting boolean mRemoteInputActive;
+    @VisibleForTesting boolean misLandscape;
+    private int mLastOrientation;
+    @VisibleForTesting CommandQueue mCommandQueue;
+
+    public RemoteInputQuickSettingsDisabler(Context context) {
+        mContext = context;
+        mCommandQueue = SysUiServiceProvider.getComponent(context, CommandQueue.class);
+        mLastOrientation = mContext.getResources().getConfiguration().orientation;
+        Dependency.get(ConfigurationController.class).addCallback(this);
+    }
+
+    public int adjustDisableFlags(int state) {
+        if (mRemoteInputActive && misLandscape) {
+            state |= StatusBarManager.DISABLE2_QUICK_SETTINGS;
+        }
+
+        return state;
+    }
+
+    public void setRemoteInputActive(boolean active){
+        if(mRemoteInputActive != active){
+            mRemoteInputActive = active;
+            recomputeDisableFlags();
+        }
+    }
+
+    @Override
+    public void onConfigChanged(Configuration newConfig) {
+        if (newConfig.orientation != mLastOrientation) {
+            misLandscape = newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE;
+            mLastOrientation = newConfig.orientation;
+            recomputeDisableFlags();
+        }
+    }
+
+    /**
+     * Reapplies the disable flags. Then the method adjustDisableFlags in this class will be invoked
+     * in {@link QSFragment#disable(int, int, boolean)} and
+     * {@link StatusBar#disable(int, int, boolean)}
+     * to modify the disable flags according to the status of mRemoteInputActive and misLandscape.
+     */
+    private void recomputeDisableFlags() {
+        mCommandQueue.recomputeDisableFlags(true);
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
index 310f14c..b814478 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/RemoteInputView.java
@@ -53,6 +53,7 @@
 
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto;
+import com.android.systemui.Dependency;
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.NotificationData;
@@ -81,6 +82,7 @@
     private RemoteInput[] mRemoteInputs;
     private RemoteInput mRemoteInput;
     private RemoteInputController mController;
+    private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
 
     private NotificationData.Entry mEntry;
 
@@ -96,6 +98,7 @@
 
     public RemoteInputView(Context context, AttributeSet attrs) {
         super(context, attrs);
+        mRemoteInputQuickSettingsDisabler = Dependency.get(RemoteInputQuickSettingsDisabler.class);
     }
 
     @Override
@@ -151,6 +154,7 @@
         mController.removeRemoteInput(mEntry, mToken);
         mEditText.mShowImeOnInputConnection = false;
         mController.remoteInputSent(mEntry);
+        mEntry.setHasSentReply();
 
         // Tell ShortcutManager that this package has been "activated".  ShortcutManager
         // will reset the throttling for this package.
@@ -232,6 +236,9 @@
                 }
             }
         }
+
+        mRemoteInputQuickSettingsDisabler.setRemoteInputActive(false);
+
         MetricsLogger.action(mContext, MetricsProto.MetricsEvent.ACTION_REMOTE_INPUT_CLOSE,
                 mEntry.notification.getPackageName());
     }
@@ -291,6 +298,9 @@
         mEditText.setSelection(mEditText.getText().length());
         mEditText.requestFocus();
         mController.addRemoteInput(mEntry, mToken);
+
+        mRemoteInputQuickSettingsDisabler.setRemoteInputActive(true);
+
         updateSendButton();
     }
 
@@ -554,6 +564,16 @@
         }
 
         @Override
+        public boolean onKeyPreIme(int keyCode, KeyEvent event) {
+            // When BACK key is pressed, this method would be invoked twice.
+            if (event.getKeyCode() == KeyEvent.KEYCODE_BACK &&
+                    event.getAction() == KeyEvent.ACTION_UP) {
+                defocusIfNeeded(true /* animate */);
+            }
+            return super.onKeyPreIme(keyCode, event);
+        }
+
+        @Override
         public boolean onCheckIsTextEditor() {
             // Stop being editable while we're being removed. During removal, we get reattached,
             // and editable views get their spellchecking state re-evaluated which is too costly
@@ -565,11 +585,6 @@
         @Override
         public InputConnection onCreateInputConnection(EditorInfo outAttrs) {
             final InputConnection inputConnection = super.onCreateInputConnection(outAttrs);
-            //if pinned, set imeOption to keep the behavior like in portrait.
-            if (mRemoteInputView != null && mRemoteInputView.mEntry.row.isPinned()) {
-                outAttrs.imeOptions |= EditorInfo.IME_FLAG_NO_EXTRACT_UI
-                        | EditorInfo.IME_FLAG_NO_FULLSCREEN;
-            }
 
             if (mShowImeOnInputConnection && inputConnection != null) {
                 final InputMethodManager imm = InputMethodManager.getInstance();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
index 585787e..924aa01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SmartReplyView.java
@@ -213,6 +213,7 @@
             Intent intent = new Intent().addFlags(Intent.FLAG_RECEIVER_FOREGROUND);
             RemoteInput.addResultsToIntent(new RemoteInput[]{remoteInput}, intent, results);
             RemoteInput.setResultsSource(intent, RemoteInput.SOURCE_CHOICE);
+            entry.setHasSentReply();
             try {
                 pendingIntent.send(context, 0, intent);
             } catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
index 4d33dec..30a5cc84 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/TintedKeyButtonDrawable.java
@@ -21,6 +21,7 @@
 import android.graphics.drawable.Drawable;
 
 import com.android.internal.graphics.ColorUtils;
+import com.android.systemui.statusbar.phone.ShadowKeyDrawable;
 
 /**
  * Drawable for {@link KeyButtonView}s which contains a single asset and colors for light and dark
@@ -36,7 +37,8 @@
 
     public static TintedKeyButtonDrawable create(Drawable drawable, @ColorInt int lightColor,
             @ColorInt int darkColor) {
-        return new TintedKeyButtonDrawable(new Drawable[] { drawable }, lightColor, darkColor);
+        return new TintedKeyButtonDrawable(new Drawable[] { drawable },
+                lightColor, darkColor);
     }
 
     private TintedKeyButtonDrawable(Drawable[] drawables, int lightColor, int darkColor){
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
index 91a4b07..db3f0d9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/AmbientState.java
@@ -30,7 +30,6 @@
 import com.android.systemui.statusbar.policy.HeadsUpManager;
 
 import java.util.ArrayList;
-import java.util.Collection;
 
 /**
  * A global state to track all input states for the algorithm.
@@ -72,6 +71,7 @@
     private ExpandableNotificationRow mExpandingNotification;
     private int mDarkTopPadding;
     private float mDarkAmount;
+    private boolean mAppearing;
 
     public AmbientState(Context context) {
         reload(context);
@@ -436,4 +436,12 @@
     public int getDarkTopPadding() {
         return mDarkTopPadding;
     }
+
+    public void setAppearing(boolean appearing) {
+        mAppearing = appearing;
+    }
+
+    public boolean isAppearing() {
+        return mAppearing;
+    }
 }
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 3c3eb6b..425c5d2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/NotificationStackScrollLayout.java
@@ -388,6 +388,7 @@
                     return object.getDarkAmount();
                 }
             };
+    private ObjectAnimator mDarkAmountAnimator;
     private boolean mUsingLightTheme;
     private boolean mQsExpanded;
     private boolean mForwardScrollable;
@@ -760,7 +761,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 +772,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);
@@ -885,7 +887,9 @@
         float appearEndPosition = getAppearEndPosition();
         float appearStartPosition = getAppearStartPosition();
         float appearFraction = 1.0f;
-        if (height >= appearEndPosition) {
+        boolean appearing = height < appearEndPosition;
+        mAmbientState.setAppearing(appearing);
+        if (!appearing) {
             translationY = 0;
             if (mShouldShowShelfOnly) {
                 stackHeight = mTopPadding + mShelf.getIntrinsicHeight();
@@ -3290,6 +3294,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
@@ -3388,7 +3402,7 @@
                             .animateY(mShelf));
             ev.darkAnimationOriginIndex = mDarkAnimationOriginIndex;
             mAnimationEvents.add(ev);
-            startBackgroundFade();
+            startDarkAmountAnimation();
         }
         mDarkNeedsAnimation = false;
     }
@@ -3966,6 +3980,9 @@
             mDarkAnimationOriginIndex = findDarkAnimationOriginIndex(touchWakeUpScreenLocation);
             mNeedsAnimation =  true;
         } else {
+            if (mDarkAmountAnimator != null) {
+                mDarkAmountAnimator.cancel();
+            }
             setDarkAmount(dark ? 1f : 0f);
             updateBackground();
         }
@@ -4010,12 +4027,22 @@
         return mDarkAmount;
     }
 
-    private void startBackgroundFade() {
-        ObjectAnimator fadeAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount,
+    private void startDarkAmountAnimation() {
+        ObjectAnimator darkAnimator = ObjectAnimator.ofFloat(this, DARK_AMOUNT, mDarkAmount,
                 mAmbientState.isDark() ? 1f : 0);
-        fadeAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
-        fadeAnimator.setInterpolator(Interpolators.ALPHA_IN);
-        fadeAnimator.start();
+        darkAnimator.setDuration(StackStateAnimator.ANIMATION_DURATION_WAKEUP);
+        darkAnimator.setInterpolator(Interpolators.ALPHA_IN);
+        darkAnimator.addListener(new AnimatorListenerAdapter() {
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                mDarkAmountAnimator = null;
+            }
+        });
+        if (mDarkAmountAnimator != null) {
+            mDarkAmountAnimator.cancel();
+        }
+        mDarkAmountAnimator = darkAnimator;
+        mDarkAmountAnimator.start();
     }
 
     private int findDarkAnimationOriginIndex(@Nullable PointF screenLocation) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
index 85f33d7..0d50f5a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/stack/StackScrollAlgorithm.java
@@ -478,22 +478,6 @@
                 childState.hidden = false;
             }
         }
-        // Let's hide all the views if we are not expanded. the views might otherwise be visible
-        // in the headsup area if a view was swiped away
-        if (!mIsExpanded) {
-            for (int i = 0; i < childCount; i++) {
-                boolean visible = false;
-                View child = algorithmState.visibleChildren.get(i);
-                if (child instanceof ExpandableNotificationRow) {
-                    ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-                    visible = row.isHeadsUp() || row.isHeadsUpAnimatingAway();
-                }
-                if (!visible) {
-                    ExpandableViewState childState = resultState.getViewStateForView(child);
-                    childState.hidden = true;
-                }
-            }
-        }
     }
 
     private void clampHunToTop(AmbientState ambientState, ExpandableNotificationRow row,
@@ -536,6 +520,10 @@
 
         int shelfStart = ambientState.getInnerHeight()
                 - ambientState.getShelf().getIntrinsicHeight();
+        if (ambientState.isAppearing() && !child.isAboveShelf()) {
+            // Don't show none heads-up notifications while in appearing phase.
+            childViewState.yTranslation = Math.max(childViewState.yTranslation, shelfStart);
+        }
         childViewState.yTranslation = Math.min(childViewState.yTranslation, shelfStart);
         if (childViewState.yTranslation >= shelfStart) {
             childViewState.hidden = !child.isExpandAnimationRunning() && !child.hasExpandingChild();
diff --git a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
index d527465..2f8dfdc 100644
--- a/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/usb/StorageNotification.java
@@ -640,7 +640,7 @@
     }
 
     private PendingIntent buildBrowsePendingIntent(VolumeInfo vol) {
-        final Intent intent = vol.buildBrowseIntent();
+        final Intent intent = vol.buildBrowseIntentForUser(vol.getMountUserId());
 
         final int requestKey = vol.getId().hashCode();
         return PendingIntent.getActivityAsUser(mContext, requestKey, intent,
diff --git a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
index ad20900..11c72c4 100644
--- a/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/util/leak/RotationUtils.java
@@ -23,6 +23,7 @@
     public static final int ROTATION_NONE = 0;
     public static final int ROTATION_LANDSCAPE = 1;
     public static final int ROTATION_SEASCAPE = 2;
+    public static final int ROTATION_UPSIDE_DOWN = 3;
 
     public static int getRotation(Context context) {
         Configuration config = context.getResources().getConfiguration();
@@ -36,4 +37,19 @@
         }
         return ROTATION_NONE;
     }
+
+    public static int getExactRotation(Context context) {
+        Configuration config = context.getResources().getConfiguration();
+        int rot = context.getDisplay().getRotation();
+        if (config.smallestScreenWidthDp < 600) {
+            if (rot == Surface.ROTATION_90) {
+                return ROTATION_LANDSCAPE;
+            } else if (rot == Surface.ROTATION_270) {
+                return ROTATION_SEASCAPE;
+            } else if (rot == Surface.ROTATION_180) {
+                return ROTATION_UPSIDE_DOWN;
+            }
+        }
+        return ROTATION_NONE;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
index 8034345..bf962b8 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/CarVolumeDialogImpl.java
@@ -344,13 +344,17 @@
       int supplementalIconId, @Nullable View.OnClickListener supplementalIconOnClickListener) {
     SeekbarListItem listItem = new SeekbarListItem(mContext);
     listItem.setMax(getMaxSeekbarValue(mCarAudioManager, volumeGroupId));
+    int color = mContext.getResources().getColor(R.color.car_volume_dialog_tint);
     int progress = getSeekbarValue(mCarAudioManager, volumeGroupId);
     listItem.setProgress(progress);
     listItem.setOnSeekBarChangeListener(
         new CarVolumeDialogImpl.VolumeSeekBarChangeListener(volumeGroupId, mCarAudioManager));
-    listItem.setPrimaryActionIcon(mContext.getResources().getDrawable(volumeItem.icon));
+    Drawable primaryIcon = mContext.getResources().getDrawable(volumeItem.icon);
+    primaryIcon.setTint(color);
+    listItem.setPrimaryActionIcon(primaryIcon);
     if (supplementalIconId != 0) {
       Drawable supplementalIcon = mContext.getResources().getDrawable(supplementalIconId);
+      supplementalIcon.setTint(color);
       listItem.setSupplementalIcon(supplementalIcon, true,
           supplementalIconOnClickListener);
     } else {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index 9488f03..955939c 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -43,8 +43,10 @@
 import android.content.res.ColorStateList;
 import android.content.res.Configuration;
 import android.content.res.Resources;
+import android.content.res.TypedArray;
 import android.graphics.Color;
 import android.graphics.PixelFormat;
+import android.graphics.PorterDuff;
 import android.graphics.drawable.ColorDrawable;
 import android.media.AudioManager;
 import android.media.AudioSystem;
@@ -90,6 +92,7 @@
 import com.android.systemui.plugins.VolumeDialogController;
 import com.android.systemui.plugins.VolumeDialogController.State;
 import com.android.systemui.plugins.VolumeDialogController.StreamState;
+import com.android.systemui.statusbar.phone.StatusBar;
 import com.android.systemui.statusbar.policy.AccessibilityManagerWrapper;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
 
@@ -131,8 +134,10 @@
     private final AccessibilityManagerWrapper mAccessibilityMgr;
     private final Object mSafetyWarningLock = new Object();
     private final Accessibility mAccessibility = new Accessibility();
-    private final ColorStateList mActiveTint;
-    private final ColorStateList mInactiveTint;
+    private ColorStateList mActiveTint;
+    private int mActiveAlpha;
+    private ColorStateList mInactiveTint;
+    private int mInactiveAlpha;
 
     private boolean mShowing;
     private boolean mShowA11yStream;
@@ -150,8 +155,6 @@
         mController = Dependency.get(VolumeDialogController.class);
         mKeyguard = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);
         mAccessibilityMgr = Dependency.get(AccessibilityManagerWrapper.class);
-        mActiveTint = Utils.getColorAccent(mContext);
-        mInactiveTint = loadColorStateList(R.color.volume_slider_inactive);
         mDeviceProvisionedController = Dependency.get(DeviceProvisionedController.class);
     }
 
@@ -224,6 +227,11 @@
             return true;
         });
 
+        mActiveTint = Utils.getColorAccent(mContext);
+        mActiveAlpha = Color.alpha(mActiveTint.getDefaultColor());
+        mInactiveTint = Utils.getColorAttr(mContext, android.R.attr.colorForeground);
+        mInactiveAlpha = getAlphaAttr(android.R.attr.secondaryContentAlpha);
+
         mDialogRowsView = mDialog.findViewById(R.id.volume_dialog_rows);
         mRinger = mDialog.findViewById(R.id.ringer);
         mRingerIcon = mRinger.findViewById(R.id.ringer_icon);
@@ -263,8 +271,11 @@
         return mDialogView;
     }
 
-    private ColorStateList loadColorStateList(int colorResId) {
-        return ColorStateList.valueOf(mContext.getColor(colorResId));
+    private int getAlphaAttr(int attr) {
+        TypedArray ta = mContext.obtainStyledAttributes(new int[]{attr});
+        float alpha = ta.getFloat(0, 0);
+        ta.recycle();
+        return (int) (alpha * 255);
     }
 
     private boolean isLandscape() {
@@ -727,6 +738,12 @@
     }
 
     protected void onStateChangedH(State state) {
+        if (mState != null && state != null
+                && mState.ringerModeInternal != state.ringerModeInternal
+                && state.ringerModeInternal == AudioManager.RINGER_MODE_VIBRATE) {
+            mController.vibrate(VibrationEffect.get(VibrationEffect.EFFECT_HEAVY_CLICK));
+        }
+
         mState = state;
         mDynamic.clear();
         // add any new dynamic rows
@@ -884,12 +901,16 @@
         if (isActive) {
             row.slider.requestFocus();
         }
-        final ColorStateList tint = isActive && row.slider.isEnabled() ? mActiveTint
-                : mInactiveTint;
+        boolean useActiveColoring = isActive && row.slider.isEnabled();
+        final ColorStateList tint = useActiveColoring ? mActiveTint : mInactiveTint;
+        final int alpha = useActiveColoring ? mActiveAlpha : mInactiveAlpha;
         if (tint == row.cachedTint) return;
         row.slider.setProgressTintList(tint);
         row.slider.setThumbTintList(tint);
+        row.slider.setProgressBackgroundTintList(tint);
+        row.slider.setAlpha(((float) alpha) / 255);
         row.icon.setImageTintList(tint);
+        row.icon.setImageAlpha(alpha);
         row.cachedTint = tint;
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
index 3a262c2..d2e8371 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSliceViewTest.java
@@ -57,9 +57,7 @@
     public void showSlice_notifiesListener() {
         ListBuilder builder = new ListBuilder(getContext(), mSliceUri);
         AtomicBoolean notified = new AtomicBoolean();
-        mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
-            notified.set(true);
-        });
+        mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
         mKeyguardSliceView.onChanged(builder.build());
         Assert.assertTrue("Listener should be notified about slice changes.",
                 notified.get());
@@ -68,9 +66,7 @@
     @Test
     public void showSlice_emptySliceNotifiesListener() {
         AtomicBoolean notified = new AtomicBoolean();
-        mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
-            notified.set(true);
-        });
+        mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
         mKeyguardSliceView.onChanged(null);
         Assert.assertTrue("Listener should be notified about slice changes.",
                 notified.get());
@@ -92,9 +88,7 @@
     @Test
     public void refresh_replacesSliceContentAndNotifiesListener() {
         AtomicBoolean notified = new AtomicBoolean();
-        mKeyguardSliceView.setContentChangeListener((hasHeader)-> {
-            notified.set(true);
-        });
+        mKeyguardSliceView.setContentChangeListener(()-> notified.set(true));
         mKeyguardSliceView.refresh();
         Assert.assertTrue("Listener should be notified about slice changes.",
                 notified.get());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
index 2f05b06..f1bf31d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/ScreenDecorationsTest.java
@@ -36,6 +36,7 @@
 import android.content.res.Configuration;
 import android.support.test.filters.SmallTest;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 import android.view.Display;
 import android.view.View;
 import android.view.WindowManager;
@@ -54,6 +55,7 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+@RunWithLooper
 @RunWith(AndroidTestingRunner.class)
 @SmallTest
 public class ScreenDecorationsTest extends SysuiTestCase {
@@ -98,6 +100,8 @@
         mContext.getOrCreateTestableResources().addOverride(
                 com.android.internal.R.bool.config_fillMainBuiltInDisplayCutout, false);
         mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius, 0);
+        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_top, 0);
+        mContext.getOrCreateTestableResources().addOverride(dimen.rounded_corner_radius_bottom, 0);
         mContext.getOrCreateTestableResources()
                 .addOverride(dimen.rounded_corner_content_padding, 0);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
index bdeb8bc..a72fed4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationInfoTest.java
@@ -508,7 +508,6 @@
                         anyString(), eq(TEST_UID), eq(true));
     }
 
-
     @Test
     public void testCloseControls_nonNullCheckSaveListenerDoesntDelayKeepShowing()
             throws Exception {
@@ -537,6 +536,43 @@
                         anyString(), eq(TEST_UID), eq(true));
     }
 
+    @Test
+    public void testCloseControls_nonNullCheckSaveListenerDoesntDelayDismiss()
+            throws Exception {
+        NotificationInfo.CheckSaveListener listener =
+                mock(NotificationInfo.CheckSaveListener.class);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
+                10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
+                null /* onSettingsClick */, null /* onAppSettingsClick */ ,
+                false /* isNonblockable */, true /* isForBlockingHelper */,
+                true /* isUserSentimentNegative */);
+
+        mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
+
+        mTestableLooper.processAllMessages();
+        verify(listener, times(0)).checkSave(any(Runnable.class), eq(mSbn));
+    }
+
+    @Test
+    public void testCloseControls_checkSaveListenerDelaysStopNotifications()
+            throws Exception {
+        NotificationInfo.CheckSaveListener listener =
+                mock(NotificationInfo.CheckSaveListener.class);
+        mNotificationInfo.bindNotification(mMockPackageManager, mMockINotificationManager,
+                TEST_PACKAGE_NAME, mNotificationChannel /* notificationChannel */,
+                10 /* numUniqueChannelsInRow */, mSbn, listener /* checkSaveListener */,
+                null /* onSettingsClick */, null /* onAppSettingsClick */ ,
+                false /* isNonblockable */, true /* isForBlockingHelper */,
+                true /* isUserSentimentNegative */);
+
+        mNotificationInfo.findViewById(R.id.block).performClick();
+        waitForUndoButton();
+        mNotificationInfo.handleCloseControls(true /* save */, false /* force */);
+
+        mTestableLooper.processAllMessages();
+        verify(listener).checkSave(any(Runnable.class), eq(mSbn));
+    }
 
     @Test
     public void testCloseControls_blockingHelperDismissedIfShown() throws Exception {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 8340ab2..85135ac 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -16,14 +16,12 @@
 
 package com.android.systemui.statusbar.phone;
 
-import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
@@ -170,6 +168,15 @@
         verify(mBouncer, never()).setExpansion(eq(0.5f));
     }
 
+    @Test
+    public void onPanelExpansionChanged_neverTranslatesBouncerWhenWakeAndUnlock() {
+        when(mFingerprintUnlockController.getMode())
+                .thenReturn(FingerprintUnlockController.MODE_WAKE_AND_UNLOCK);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(KeyguardBouncer.EXPANSION_VISIBLE,
+                false /* tracking */);
+        verify(mBouncer, never()).setExpansion(anyFloat());
+    }
+
     private class TestableStatusBarKeyguardViewManager extends StatusBarKeyguardViewManager {
 
         public TestableStatusBarKeyguardViewManager(Context context,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
new file mode 100644
index 0000000..3b47eae
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputQuickSettingsDisablerTest.java
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file
+ * except in compliance with the License. You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the
+ * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the specific language governing
+ * permissions and limitations under the License.
+ */
+
+package com.android.systemui.statusbar.policy;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.TestCase.assertTrue;
+import static org.junit.Assert.assertFalse;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.verify;
+
+import android.content.res.Configuration;
+import android.support.test.runner.AndroidJUnit4;
+import android.test.suitebuilder.annotation.SmallTest;
+
+import com.android.systemui.SysuiTestCase;
+import com.android.systemui.statusbar.CommandQueue;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@SmallTest
+@RunWith(AndroidJUnit4.class)
+public class RemoteInputQuickSettingsDisablerTest extends SysuiTestCase {
+
+    private CommandQueue mCommandQueue;
+    private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mCommandQueue = mock(CommandQueue.class);
+        mContext.putComponent(CommandQueue.class, mCommandQueue);
+
+        mRemoteInputQuickSettingsDisabler = new RemoteInputQuickSettingsDisabler(mContext);
+    }
+
+    @Test
+    public void shouldEnableQuickSetting_afterDeactiviate() {
+        mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
+        mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
+        assertFalse(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+    }
+
+    @Test
+    public void shouldDisableQuickSetting_afteActiviate() {
+        mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.FALSE);
+        mRemoteInputQuickSettingsDisabler.setRemoteInputActive(Boolean.TRUE);
+        assertTrue(mRemoteInputQuickSettingsDisabler.mRemoteInputActive);
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+    }
+
+    @Test
+    public void testChangeToLandscape() {
+        Configuration c = new Configuration(mContext.getResources().getConfiguration());
+        c.orientation = Configuration.ORIENTATION_PORTRAIT;
+        mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+        c.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+        assertTrue(mRemoteInputQuickSettingsDisabler.misLandscape);
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+    }
+
+    @Test
+    public void testChangeToPortrait() {
+        Configuration c = new Configuration(mContext.getResources().getConfiguration());
+        c.orientation = Configuration.ORIENTATION_LANDSCAPE;
+        mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+        c.orientation = Configuration.ORIENTATION_PORTRAIT;
+        mRemoteInputQuickSettingsDisabler.onConfigChanged(c);
+        assertFalse(mRemoteInputQuickSettingsDisabler.misLandscape);
+        verify(mCommandQueue, atLeastOnce()).recomputeDisableFlags(anyBoolean());
+    }
+
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
index 938dfca..a6fa4f5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/RemoteInputViewTest.java
@@ -54,6 +54,7 @@
 
     @Mock private RemoteInputController mController;
     @Mock private ShortcutManager mShortcutManager;
+    @Mock private RemoteInputQuickSettingsDisabler mRemoteInputQuickSettingsDisabler;
     private BlockingQueueIntentReceiver mReceiver;
     private RemoteInputView mView;
 
@@ -61,6 +62,9 @@
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
 
+        mDependency.injectTestDependency(RemoteInputQuickSettingsDisabler.class,
+                mRemoteInputQuickSettingsDisabler);
+
         mReceiver = new BlockingQueueIntentReceiver();
         mContext.registerReceiver(mReceiver, new IntentFilter(TEST_ACTION), null,
                 Handler.createAsync(Dependency.get(Dependency.BG_LOOPER)));
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index 0ca4d9a..d2990de 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -205,6 +205,14 @@
         HARDWARE_FAILURE_FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5;
     }
 
+    enum IoOperation {
+        IOOP_UNKNOWN = 0;
+        IOOP_READ = 1;
+        IOOP_WRITE = 2;
+        IOOP_UNMAP = 3;
+        IOOP_SYNC = 4;
+    }
+
   // Known visual elements: views or controls.
   enum View {
     // Unknown view
@@ -3978,27 +3986,44 @@
     // OS: O
     APP_TRANSITION_IS_EPHEMERAL = 905;
 
-    // An autofill session was started
+    // An autofill session was started.
+    // OS: O
     // Package: Package of app that is autofilled
     // NOTE: starting on OS MR1, it also added the following field:
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // NOTE: starting on OS P, it also added the following field:
-    // Tag FIELD_FLAGS - Flags used to start the session
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFIL_FLAGS: flags used to start the session.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session started.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SESSION_STARTED = 906;
 
     // An autofill request was processed by a service
-    // Type TYPE_SUCCESS: The request succeeded
-    // Type TYPE_FAILURE: The request failed
+    // Type TYPE_SUCCESS: service called FillCalback.onSuccess()
+    // Type TYPE_FAILURE: service called FillCallback.onFailure()
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets returned in the response, or -1 if
-    // the service returned a null response.
-    // NOTE: starting on OS P, it also added:
-    // Type TYPE_CLOSE: Service returned a null response.
+    // the service returned a null response
+    // NOTE: starting on OS P, it also added the following fields:
+    // TYPE_CLOSE: request timed out before service called a FillCallback method
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_REQUEST_ORDINAL: sequence number of the request inside a session; starts
+    //     with 1.
+    // Tag FIELD_AUTOFILL_FLAGS: flags used to request autofill
+    // Tag FIELD_AUTOFILL_DURATION: how long it took (in ms) to show the autofill UI after a field
+    //     was focused.
+    // Tag FIELD_AUTOFILL_AUTHENTICATION_STATUS: status of authenticated datasets or responses.
     // Tag FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS: if service requested field classification,
-    // number of entries field ids in the request.
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    //     number of entries field ids in the request.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: Prior to P, some of the fields above were logged by 5 different metrics:
+    // - AUTOFILL_UI_LATENCY
+    // - AUTOFILL_AUTHENTICATED;
+    // - AUTOFILL_DATASET_AUTHENTICATED
+    // - AUTOFILL_INVALID_AUTHENTICATION
+    // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
     AUTOFILL_REQUEST = 907;
 
     // Tag of a field for a package of an autofill service
@@ -4015,9 +4040,11 @@
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_FILTERTEXT_LEN: The length of the filter text
     // Tag FIELD_AUTOFILL_NUM_DATASETS: The number of datasets shown
-    // NOTE: starting on OS P, it also added the following field:
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FILL_UI = 910;
 
     // Tag of a field for the length of the filter text
@@ -4026,16 +4053,17 @@
     // An autofill authentication succeeded
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_AUTHENTICATED = 912;
 
     // An activity was autofilled and all values could be applied
     // Package: Package of app that is autofilled
     // Tag FIELD_AUTOFILL_NUM_VALUES: Number of values that were suggested to be autofilled
     // Tag FIELD_AUTOFILL_NUM_VIEWS_FILLED: Number of views that could be filled
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_DATASET_APPLIED = 913;
 
     // Tag of a field for the number values to be filled in
@@ -4050,28 +4078,37 @@
     // Type TYPE_ACTION: data was saved
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_NUM_IDS: The number of ids that are saved
-    // NOTE: starting on OS P, it also added the following field:
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_UI = 916;
 
     // Tag of a field for the number of saveable ids
     FIELD_AUTOFILL_NUM_IDS = 917;
 
-    // ACTION: An autofill service was reqiested to save data
+    // ACTION: An autofill service was requested to save data
     // Type TYPE_SUCCESS: The request succeeded right away
     // Type TYPE_OPEN: The request succeeded but the service launched an IntentSender
     // Type TYPE_FAILURE: The request failed
     // Package: Package of app that was autofilled
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_DATA_SAVE_REQUEST = 918;
 
     // An auto-fill session was finished
+    // OS: O
     // Package: Package of app that was autofilled
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_NUMBER_REQUESTS: number of requests made to the service (each request
+    //     is logged by a separate AUTOFILL_REQUEST metric)
     AUTOFILL_SESSION_FINISHED = 919;
 
     // meta-event: a reader has checkpointed the log here.
@@ -4198,7 +4235,7 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of the autofill service that processed the request
     // TAG FIELD_AUTOFILL_FORGED_COMPONENT_NAME: Component name being forged
     // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FORGED_COMPONENT_ATTEMPT = 948;
 
     // FIELD - The component that an app tried tro forged.
@@ -4656,8 +4693,10 @@
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_PREVIOUS_LENGTH: the previous length of the value
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_VALUE_RESET = 1124;
 
     // Tag of AUTOFILL_VALUE_RESET
@@ -4667,25 +4706,21 @@
     // An autofill dataset authentication succeeded
     // Package: Package of app that was autofilled
     // OS: O MR
-    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_DATASET_AUTHENTICATED = 1126;
 
     // An autofill service provided an invalid dataset authentication
     // Package: Package of app that was autofilled
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_INVALID_DATASET_AUTHENTICATION = 1127;
 
     // An autofill service provided an invalid authentication extra
     // Package: Package of app that was autofilled
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, this metric became a value for FIELD_AUTOFILL_AUTHENTICATION_STATUS
     AUTOFILL_INVALID_AUTHENTICATION = 1128;
 
     // An autofill service used a custom description (using RemoteViews) in the autofill save UI
@@ -4693,8 +4728,10 @@
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_CUSTOM_DESCRIPTION = 1129;
 
     // FIELD - Type of save object passed by the service when the Save UI is shown
@@ -4706,8 +4743,10 @@
     // OS: O MR
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_CUSTOM_SUBTITLE = 1131;
 
     // User tapped a link in the custom description of the autofill save UI provided by an autofill service
@@ -4718,8 +4757,10 @@
     // Type TYPE_FAILURE: The link could not launc an activity
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_LINK_TAPPED = 1132;
 
     // Result of the validation on save when an autofill service provided a validator
@@ -4730,8 +4771,10 @@
     // Type TYPE_DISMISS: The validation failed
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_SAVE_TYPE: Type of save object passed by the service
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_VALIDATION = 1133;
 
     // Result of an operation in the autofill save UI after the user tapped a link in the custom description
@@ -4741,8 +4784,10 @@
     // Type TYPE_OPEN: The autofill save UI was restored
     // Type TYPE_DISMISS: The autofill save UI was destroyed
     // Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // NOTE: starting on OS P, it also added the following fields:
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
 
     // Autofill service called API that disables itself
@@ -4750,13 +4795,12 @@
     // OS: O MR
     AUTOFILL_SERVICE_DISABLED_SELF = 1135;
 
+    // DEPRECATED - on P it was merged with AUTOFILL_REQUEST
     // Reports how long it took to show the autofill UI after a field was focused
     // Tag FIELD_AUTOFILL_DURATION: Duration in ms
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Package: Package of the autofill service
     // OS: O MR
-    // NOTE: starting on OS P, it also added the following field:
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_UI_LATENCY = 1136;
 
     // Action: the snooze leave-behind was shown after the user clicked the snooze icon
@@ -4923,15 +4967,19 @@
     // An autofill service explicitly defined which view should commit the autofill context
     // Package: Package of app that is autofilled
     // OS: P
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_EXPLICIT_SAVE_TRIGGER_DEFINITION = 1228;
 
     // The autofill context was commited when the user clicked a view explicitly marked by the
     // service as committing it
     // Package: Package of app that is autofilled
     // OS: P
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SAVE_EXPLICITLY_TRIGGERED = 1229;
 
     // OPEN: Settings > Network & Internet > Mobile network > Wi-Fi calling
@@ -4944,7 +4992,8 @@
     // OS: P
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SERVICE_DISABLED_APP = 1231;
 
     // An autofill service asked to disable autofill for a given activity.
@@ -4953,7 +5002,8 @@
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_CLASS_NAME: Class name of the activity that is being disabled for autofill
     // Tag FIELD_AUTOFILL_DURATION: duration (in ms) that autofill will be disabled
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_SERVICE_DISABLED_ACTIVITY = 1232;
 
     // ACTION: Stop an app and turn on background check
@@ -5163,9 +5213,11 @@
     // Package: Package of app that is autofilled
     // Counter: number of matches found
     // OS: P
+    // Tag FIELD_CLASS_NAME: Class name of the activity that is autofilled.
     // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
     // Tag FIELD_AUTOFILL_MATCH_SCORE: Average score of the matches, in the range of 0 to 100
-    // Type FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
+    // Tag FIELD_AUTOFILL_SESSION_ID: id of the autofill session associated with this metric.
+    // Tag FIELD_AUTOFILL_COMPAT_MODE: package is being autofilled on compatibility mode.
     AUTOFILL_FIELD_CLASSIFICATION_MATCHES = 1273;
 
     // Tag used to report autofill field classification scores
@@ -5832,6 +5884,7 @@
     ACTION_STORAGE_MIGRATE_LATER = 1413;
 
     // Tag used to report whether an activity is being autofilled  on compatibility mode.
+    // OS: P
     FIELD_AUTOFILL_COMPAT_MODE = 1414;
 
     // OPEN: Settings > Sound > Switch a2dp devices dialog
@@ -5931,8 +5984,7 @@
     // ACTION: Battery health snapshot
     // CATEGORY: OTHER
     // OS: P
-    // uses FIELD_END_BATTERY_PERCENT for batt %
-    // uses FIELD_END_BATTERY_UA for instantaneous current load
+    // uses FIELD_END_BATTERY_PERCENT for instantaneous batt %
     ACTION_BATTERY_HEALTH = 1433;
 
     // FIELD: Battery health snapshot type - min daily voltage, resistance, etc.
@@ -5940,31 +5992,33 @@
     // OS: P
     FIELD_BATTERY_HEALTH_SNAPSHOT_TYPE = 1434;
 
-    // FIELD: Battery temperature at snapshop.
+    // FIELD: Battery temperature at snapshot, in 1/10 deg C.
     // CATEGORY: OTHER
     // OS: P
-    FIELD_BATTERY_TEMPERATURE = 1435;
+    FIELD_BATTERY_TEMPERATURE_DECI_C = 1435;
 
-    // FIELD: Battery voltage at snapshot.
+    // FIELD: Battery voltage at snapshot, in microVolts.
     // CATEGORY: OTHER
     // OS: P
-    FIELD_BATTERY_VOLTAGE = 1436;
+    FIELD_BATTERY_VOLTAGE_UV = 1436;
 
-    // FIELD: Battery open circuit voltage at snapshot.
+    // FIELD: Battery open circuit voltage at snapshot, in microVolts.
     // CATEGORY: OTHER
     // OS: P
-    FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE = 1437;
+    FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE_UV = 1437;
 
-    // ACTION: Battery charge cycles
-    //         Number of times the battery has charged beyond a
+    // ACTION: Number of times the battery has charged beyond a
     //         fractional threshold of full capacity.
     // CATEGORY: OTHER
     // OS: P
     ACTION_BATTERY_CHARGE_CYCLES = 1438;
 
-    // FIELD: Battery charge cycles
-    //        Number of times the battery has charged beyond a
-    //        fractional threshold of full capacity.
+    // FIELD: BATTERY_CHARGE_CYCLES - Number of times the battery has charged
+    //                                beyond a fractional threshold of full
+    //                                capacity.  A comma-separated string of
+    //                                buckets.  If there are eight buckets,
+    //                                each bucket represents charging to n/8
+    //                                percent full.
     // CATEGORY: OTHER
     // OS: P
     FIELD_BATTERY_CHARGE_CYCLES = 1439;
@@ -5980,6 +6034,88 @@
     // OS: P
     DIALOG_BLUETOOTH_DISABLE_A2DP_HW_OFFLOAD = 1441;
 
+    // ACTION: SLOW_IO - I/O operation took longer than threshold,
+    //                   reported aggregated per day when > 0.
+    // CATEGORY: OTHER
+    // OS: P
+    ACTION_SLOW_IO = 1442;
+
+    // FIELD: IO_OPERATION_TYPE - The IO Operation that caused the high latency.
+    //        The value is an integer from the enum IoOperation.
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_IO_OPERATION_TYPE = 1443;
+
+    // FIELD: IO_OPERATION_COUNT - Count of how many times this slow IO operation happened
+    //                over the past 24hr (reported only if > 0).
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_IO_OPERATION_COUNT = 1444;
+
+    // ACTION: Speaker Imedance - last recorded speaker impedance.
+    //                            reported max once per 24hr.
+    // CATEGORY: OTHER
+    // OS: P
+    ACTION_SPEAKER_IMPEDANCE = 1445;
+
+    // FIELD: Speaker Impedance in milliohms.
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_SPEAKER_IMPEDANCE_MILLIOHMS = 1446;
+
+    // FIELD: Speaker Location - identifies one of several speakers on a device.
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_SPEAKER_LOCATION = 1447;
+
+    // FIELD: Instantaneous battery resistance in microohms.
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_BATTERY_RESISTANCE_UOHMS = 1448;
+
+    // FIELD: Instantaneous battery current - in microamps.
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_BATTERY_CURRENT_UA = 1449;
+
+    // FIELD: HARDWARE_LOCATION - Identifier for instance of a hardware type on a
+    //                            board.
+    // CATEGORY: OTHER
+    // OS: P
+    FIELD_HARDWARE_LOCATION = 1450;
+
+    // ACTION: BATTERY_CAUSED_SHUTDOWN - shutdown due to low battery, the
+    //                  action is logged after the subsequent boot.
+    // CATEGORY: OTHER
+    // OS: P
+    ACTION_BATTERY_CAUSED_SHUTDOWN = 1451;
+
+    // FIELD: Flags used on autofill-related metrics
+    // OS: P
+    FIELD_AUTOFILL_FLAGS = 1452;
+
+    // Tag used when the service returned an authenticated dataset or response.
+    // Used to replace the following individual metrics, which now are logged as the value of this
+    // field in the AUTOFILL_REQUEST metric:
+    // - AUTOFILL_AUTHENTICATED;
+    // - AUTOFILL_DATASET_AUTHENTICATED
+    // - AUTOFILL_INVALID_AUTHENTICATION
+    // - AUTOFILL_INVALID_DATASET_AUTHENTICATION
+    // OS: P
+    FIELD_AUTOFILL_AUTHENTICATION_STATUS = 1453;
+
+    // FIELD: Index of the autofill request inside of a session.
+    // OS: P
+    FIELD_AUTOFILL_REQUEST_ORDINAL = 1454;
+
+    // FIELD: Number of requests made to an autofill service during a session.
+    // OS: P
+    FIELD_AUTOFILL_NUMBER_REQUESTS = 1455;
+
+    // FIELD: Id of the autofill session associated with this metric.
+    // OS: P
+    FIELD_AUTOFILL_SESSION_ID = 1456;
+
     // ---- End P Constants, all P constants go above this line ----
 
     // First Q constant in master goes here:
diff --git a/proto/src/wifi.proto b/proto/src/wifi.proto
index 9ff8e7d..72f11e0 100644
--- a/proto/src/wifi.proto
+++ b/proto/src/wifi.proto
@@ -453,6 +453,10 @@
 
   // Number of times the firmware picked a SoftAp channel not satisfying user band preference.
   optional int32 num_soft_ap_user_band_preference_unsatisfied = 116;
+
+  // Identifier for experimental scoring parameter settings.
+  optional string score_experiment_id = 117;
+
 }
 
 // Information that gets logged for every WiFi connection.
@@ -615,6 +619,9 @@
 
   // Number of RSSI polls with 'rssi'
   optional int32 count = 2;
+
+  // Beacon frequency of the channel in MHz
+  optional int32 frequency = 3;
 }
 
 // Number of occurrences of a specific alert reason value
diff --git a/services/art-profile b/services/art-profile
index a372a9c..0fdbf6b 100644
--- a/services/art-profile
+++ b/services/art-profile
@@ -3272,11 +3272,11 @@
 Lcom/android/server/soundtrigger/SoundTriggerService$SoundTriggerServiceStub;
 Lcom/android/server/soundtrigger/SoundTriggerService;
 Lcom/android/server/stats/StatsCompanionService$1;
-Lcom/android/server/stats/StatsCompanionService$AnomalyAlarmReceiver;
+Lcom/android/server/stats/StatsCompanionService$AnomalyAlarmListener;
 Lcom/android/server/stats/StatsCompanionService$AppUpdateReceiver;
 Lcom/android/server/stats/StatsCompanionService$Lifecycle;
-Lcom/android/server/stats/StatsCompanionService$PeriodicAlarmReceiver;
-Lcom/android/server/stats/StatsCompanionService$PullingAlarmReceiver;
+Lcom/android/server/stats/StatsCompanionService$PeriodicAlarmListener;
+Lcom/android/server/stats/StatsCompanionService$PullingAlarmListener;
 Lcom/android/server/stats/StatsCompanionService$ShutdownEventReceiver;
 Lcom/android/server/stats/StatsCompanionService$StatsdDeathRecipient;
 Lcom/android/server/stats/StatsCompanionService;
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index d97253e..1ccce17 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -537,11 +537,17 @@
             final String callingPackage = packages != null ? packages[0] : "uid-" + callingUid;
             Slog.w(TAG, "App (package=" + callingPackage + ", UID=" + callingUid
                     + ") passed component (" + componentName + ") owned by UID " + packageUid);
-            mMetricsLogger.write(
-                    Helper.newLogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT,
-                            callingPackage, getServicePackageName(), compatMode)
+
+            // NOTE: not using Helper.newLogMaker() because we don't have the session id
+            final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_FORGED_COMPONENT_ATTEMPT)
+                    .setPackageName(callingPackage)
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FORGED_COMPONENT_NAME,
-                            componentName == null ? "null" : componentName.flattenToShortString()));
+                            componentName == null ? "null" : componentName.flattenToShortString());
+            if (compatMode) {
+                log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+            }
+            mMetricsLogger.write(log);
 
             throw new SecurityException("Invalid component: " + componentName);
         }
@@ -780,10 +786,10 @@
             @Nullable ArrayList<String> changedDatasetIds,
             @Nullable ArrayList<AutofillId> manuallyFilledFieldIds,
             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
-            @NonNull String appPackageName, boolean compatMode) {
+            @NonNull ComponentName appComponentName, boolean compatMode) {
         logContextCommittedLocked(sessionId, clientState, selectedDatasets, ignoredDatasets,
                 changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
-                manuallyFilledDatasetIds, null, null, appPackageName, compatMode);
+                manuallyFilledDatasetIds, null, null, appComponentName, compatMode);
     }
 
     @GuardedBy("mLock")
@@ -796,7 +802,7 @@
             @Nullable ArrayList<ArrayList<String>> manuallyFilledDatasetIds,
             @Nullable ArrayList<AutofillId> detectedFieldIdsList,
             @Nullable ArrayList<FieldClassification> detectedFieldClassificationsList,
-            @NonNull String appPackageName, boolean compatMode) {
+            @NonNull ComponentName appComponentName, boolean compatMode) {
         if (isValidEventLocked("logDatasetNotSelected()", sessionId)) {
             if (sVerbose) {
                 Slog.v(TAG, "logContextCommitted() with FieldClassification: id=" + sessionId
@@ -807,6 +813,7 @@
                         + ", manuallyFilledFieldIds=" + manuallyFilledFieldIds
                         + ", detectedFieldIds=" + detectedFieldIdsList
                         + ", detectedFieldClassifications=" + detectedFieldClassificationsList
+                        + ", appComponentName=" + appComponentName.toShortString()
                         + ", compatMode=" + compatMode);
             }
             AutofillId[] detectedFieldsIds = null;
@@ -834,7 +841,7 @@
                 final int averageScore = (int) ((totalScore * 100) / totalSize);
                 mMetricsLogger.write(Helper
                         .newLogMaker(MetricsEvent.AUTOFILL_FIELD_CLASSIFICATION_MATCHES,
-                                appPackageName, getServicePackageName(), compatMode)
+                                appComponentName, getServicePackageName(), sessionId, compatMode)
                         .setCounterValue(numberFields)
                         .addTaggedData(MetricsEvent.FIELD_AUTOFILL_MATCH_SCORE,
                                 averageScore));
@@ -889,9 +896,11 @@
             }
             mUserData = userData;
             // Log it
-            int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
-            mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED,
-                    getServicePackageName(), null)
+            final int numberFields = mUserData == null ? 0: mUserData.getCategoryIds().length;
+            // NOTE: contrary to most metrics, the service name is logged as the main package name
+            // here, not as MetricsEvent.FIELD_AUTOFILL_SERVICE
+            mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_USERDATA_UPDATED)
+                    .setPackageName(getServicePackageName())
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_VALUES, numberFields));
         }
     }
@@ -1130,7 +1139,8 @@
     /**
      * Called by {@link Session} when service asked to disable autofill for an app.
      */
-    void disableAutofillForApp(@NonNull String packageName, long duration, boolean compatMode) {
+    void disableAutofillForApp(@NonNull String packageName, long duration, int sessionId,
+            boolean compatMode) {
         synchronized (mLock) {
             if (mDisabledApps == null) {
                 mDisabledApps = new ArrayMap<>(1);
@@ -1143,7 +1153,7 @@
             mDisabledApps.put(packageName, expiration);
             int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
             mMetricsLogger.write(Helper.newLogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_APP,
-                    packageName, getServicePackageName(), compatMode)
+                    packageName, getServicePackageName(), sessionId, compatMode)
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration));
         }
     }
@@ -1152,7 +1162,7 @@
      * Called by {@link Session} when service asked to disable autofill an app.
      */
     void disableAutofillForActivity(@NonNull ComponentName componentName, long duration,
-            boolean compatMode) {
+            int sessionId, boolean compatMode) {
         synchronized (mLock) {
             if (mDisabledActivities == null) {
                 mDisabledActivities = new ArrayMap<>(1);
@@ -1163,14 +1173,20 @@
                 expiration = Long.MAX_VALUE;
             }
             mDisabledActivities.put(componentName, expiration);
-            final int intDuration = duration > Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) duration;
+            final int intDuration = duration > Integer.MAX_VALUE
+                    ? Integer.MAX_VALUE
+                    : (int) duration;
             // NOTE: not using Helper.newLogMaker() because we're setting the componentName instead
             // of package name
-            mMetricsLogger.write(new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
+            final LogMaker log = new LogMaker(MetricsEvent.AUTOFILL_SERVICE_DISABLED_ACTIVITY)
                     .setComponentName(componentName)
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, getServicePackageName())
                     .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, intDuration)
-                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0));
+                    .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId);
+            if (compatMode) {
+                log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
+            }
+            mMetricsLogger.write(log);
         }
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/Helper.java b/services/autofill/java/com/android/server/autofill/Helper.java
index f781013..cf310e9 100644
--- a/services/autofill/java/com/android/server/autofill/Helper.java
+++ b/services/autofill/java/com/android/server/autofill/Helper.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.app.assist.AssistStructure;
 import android.app.assist.AssistStructure.ViewNode;
+import android.content.ComponentName;
 import android.metrics.LogMaker;
 import android.service.autofill.Dataset;
 import android.util.ArrayMap;
@@ -109,20 +110,29 @@
     }
 
     @NonNull
-    public static LogMaker newLogMaker(int category, String packageName,
-            String servicePackageName) {
-        final LogMaker log = new LogMaker(category).setPackageName(packageName);
-        if (servicePackageName != null) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName);
+    private static LogMaker newLogMaker(int category, @NonNull String servicePackageName,
+            int sessionId, boolean compatMode) {
+        final LogMaker log = new LogMaker(category)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE, servicePackageName)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SESSION_ID, sessionId);
+        if (compatMode) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, 1);
         }
         return log;
     }
 
     @NonNull
-    public static LogMaker newLogMaker(int category, String packageName,
-            String servicePackageName, boolean compatMode) {
-        return newLogMaker(category, packageName, servicePackageName)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE, compatMode ? 1 : 0);
+    public static LogMaker newLogMaker(int category, @NonNull String packageName,
+            @NonNull String servicePackageName, int sessionId, boolean compatMode) {
+        return newLogMaker(category, servicePackageName, sessionId, compatMode)
+                .setPackageName(packageName);
+    }
+
+    @NonNull
+    public static LogMaker newLogMaker(int category, @NonNull ComponentName componentName,
+            @NonNull String servicePackageName, int sessionId, boolean compatMode) {
+        return newLogMaker(category, servicePackageName, sessionId, compatMode)
+                .setComponentName(componentName);
     }
 
     public static void printlnRedactedText(@NonNull PrintWriter pw, @Nullable CharSequence text) {
@@ -193,6 +203,18 @@
         return urlBarNode;
     }
 
+    /**
+     * Gets the value of a metric tag, or {@code 0} if not found or NaN.
+     */
+    static int getNumericValue(@NonNull LogMaker log, int tag) {
+        final Object value = log.getTaggedData(tag);
+        if (!(value instanceof Number)) {
+            return 0;
+        } else {
+            return ((Number) value).intValue();
+        }
+    }
+
     private interface ViewNodeFilter {
         boolean matches(ViewNode node);
     }
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 4ded3fe..3e932e8 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -99,12 +99,14 @@
     private PendingRequest mPendingRequest;
 
     public interface FillServiceCallbacks {
-        void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
+        void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+                @NonNull String servicePackageName, int requestFlags);
+        void onFillRequestFailure(int requestId, @Nullable CharSequence message,
                 @NonNull String servicePackageName);
-        void onFillRequestFailure(@Nullable CharSequence message,
-                @NonNull String servicePackageName);
+        void onFillRequestTimeout(int requestId, @NonNull String servicePackageName);
         void onSaveRequestSuccess(@NonNull String servicePackageName,
                 @Nullable IntentSender intentSender);
+        // TODO(b/80093094): add timeout here too?
         void onSaveRequestFailure(@Nullable CharSequence message,
                 @NonNull String servicePackageName);
         void onServiceDied(RemoteFillService service);
@@ -301,21 +303,31 @@
         mContext.unbindService(mServiceConnection);
     }
 
-    private void dispatchOnFillRequestSuccess(PendingRequest pendingRequest, int requestFlags,
-            FillResponse response) {
+    private void dispatchOnFillRequestSuccess(@NonNull PendingFillRequest pendingRequest,
+            @Nullable FillResponse response, int requestFlags) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestSuccess(requestFlags, response,
+                mCallbacks.onFillRequestSuccess(pendingRequest.mRequest.getId(), response,
+                        mComponentName.getPackageName(), requestFlags);
+            }
+        });
+    }
+
+    private void dispatchOnFillRequestFailure(@NonNull PendingFillRequest pendingRequest,
+            @Nullable CharSequence message) {
+        mHandler.post(() -> {
+            if (handleResponseCallbackCommon(pendingRequest)) {
+                mCallbacks.onFillRequestFailure(pendingRequest.mRequest.getId(), message,
                         mComponentName.getPackageName());
             }
         });
     }
 
-    private void dispatchOnFillRequestFailure(PendingRequest pendingRequest,
-            @Nullable CharSequence message) {
+    private void dispatchOnFillRequestTimeout(@NonNull PendingFillRequest pendingRequest) {
         mHandler.post(() -> {
             if (handleResponseCallbackCommon(pendingRequest)) {
-                mCallbacks.onFillRequestFailure(message, mComponentName.getPackageName());
+                mCallbacks.onFillRequestTimeout(pendingRequest.mRequest.getId(),
+                        mComponentName.getPackageName());
             }
         });
     }
@@ -538,18 +550,18 @@
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
-                                request.getFlags(), response);
+                                response, request.getFlags());
                     }
                 }
 
                 @Override
-                public void onFailure(CharSequence message) {
+                public void onFailure(int requestId, CharSequence message) {
                     if (!finish()) return;
 
                     final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
-                        remoteService.dispatchOnFillRequestFailure(
-                                PendingFillRequest.this, message);
+                        remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this,
+                                message);
                     }
                 }
             };
@@ -566,7 +578,7 @@
             if (cancellation != null) {
                 remoteService.dispatchOnFillTimeout(cancellation);
             }
-            remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
+            remoteService.dispatchOnFillRequestTimeout(PendingFillRequest.this);
         }
 
         @Override
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 4b67bb1..09f4135 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -27,6 +27,7 @@
 import static android.view.autofill.AutofillManager.ACTION_VIEW_EXITED;
 
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.autofill.Helper.getNumericValue;
 import static com.android.server.autofill.Helper.sDebug;
 import static com.android.server.autofill.Helper.sPartitionMaxCount;
 import static com.android.server.autofill.Helper.sVerbose;
@@ -93,6 +94,7 @@
 import com.android.server.autofill.ui.PendingUi;
 
 import java.io.PrintWriter;
+import java.io.StringWriter;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -176,7 +178,7 @@
 
     /**
      * Contexts read from the app; they will be updated (sanitized, change values for save) before
-     * sent to {@link AutofillService}. Ordered by the time they we read.
+     * sent to {@link AutofillService}. Ordered by the time they were read.
      */
     @GuardedBy("mLock")
     private ArrayList<FillContext> mContexts;
@@ -231,6 +233,12 @@
     private final LocalLog mWtfHistory;
 
     /**
+     * Map of {@link MetricsEvent#AUTOFILL_REQUEST} metrics, keyed by fill request id.
+     */
+    @GuardedBy("mLock")
+    private final SparseArray<LogMaker> mRequestLogs = new SparseArray<>(1);
+
+    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IAssistDataReceiver mAssistReceiver = new IAssistDataReceiver.Stub() {
@@ -483,8 +491,18 @@
             requestId = sIdCounter.getAndIncrement();
         } while (requestId == INVALID_REQUEST_ID);
 
+        // Create a metrics log for the request
+        final int ordinal = mRequestLogs.size() + 1;
+        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL, ordinal);
+        if (flags != 0) {
+            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags);
+        }
+        mRequestLogs.put(requestId, log);
+
         if (sVerbose) {
-            Slog.v(TAG, "Requesting structure for requestId=" + requestId + ", flags=" + flags);
+            Slog.v(TAG, "Requesting structure for request #" + ordinal + " ,requestId="
+                    + requestId + ", flags=" + flags);
         }
 
         // If the focus changes very quickly before the first request is returned each focus change
@@ -537,7 +555,7 @@
         setClientLocked(client);
 
         mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_STARTED)
-                .addTaggedData(MetricsEvent.FIELD_FLAGS, flags));
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FLAGS, flags));
     }
 
     /**
@@ -604,21 +622,30 @@
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestSuccess(int requestFlags, @Nullable FillResponse response,
-            @NonNull String servicePackageName) {
+    public void onFillRequestSuccess(int requestId, @Nullable FillResponse response,
+            @NonNull String servicePackageName, int requestFlags) {
         final AutofillId[] fieldClassificationIds;
 
+        final LogMaker requestLog;
+
         synchronized (mLock) {
             if (mDestroyed) {
                 Slog.w(TAG, "Call to Session#onFillRequestSuccess() rejected - session: "
                         + id + " destroyed");
                 return;
             }
+
+            requestLog = mRequestLogs.get(requestId);
+            if (requestLog != null) {
+                requestLog.setType(MetricsEvent.TYPE_SUCCESS);
+            } else {
+                Slog.w(TAG, "onFillRequestSuccess(): no request log for id " + requestId);
+            }
             if (response == null) {
+                if (requestLog != null) {
+                    requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1);
+                }
                 processNullResponseLocked(requestFlags);
-                mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                        .setType(MetricsEvent.TYPE_SUCCESS)
-                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS, -1));
                 return;
             }
 
@@ -645,10 +672,11 @@
                 Slog.d(TAG, message.toString());
             }
             if ((flags & FillResponse.FLAG_DISABLE_ACTIVITY_ONLY) != 0) {
-                mService.disableAutofillForActivity(mComponentName, disableDuration, mCompatMode);
+                mService.disableAutofillForActivity(mComponentName, disableDuration,
+                        id, mCompatMode);
             } else {
                 mService.disableAutofillForApp(mComponentName.getPackageName(), disableDuration,
-                        mCompatMode);
+                        id, mCompatMode);
             }
             sessionFinishedState = AutofillManager.STATE_DISABLED_BY_SERVICE;
         }
@@ -659,38 +687,54 @@
             // Response is "empty" from an UI point of view, need to notify client.
             notifyUnavailableToClient(sessionFinishedState);
         }
+
+        if (requestLog != null) {
+            requestLog.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
+                            response.getDatasets() == null ? 0 : response.getDatasets().size());
+            if (fieldClassificationIds != null) {
+                requestLog.addTaggedData(
+                        MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
+                        fieldClassificationIds.length);
+            }
+        }
+
         synchronized (mLock) {
             processResponseLocked(response, null, requestFlags);
         }
-
-        final LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_SUCCESS)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
-                        response.getDatasets() == null ? 0 : response.getDatasets().size());
-        if (fieldClassificationIds != null) {
-            log.addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS,
-                    fieldClassificationIds.length);
-        }
-        mMetricsLogger.write(log);
     }
 
     // FillServiceCallbacks
     @Override
-    public void onFillRequestFailure(@Nullable CharSequence message,
+    public void onFillRequestFailure(int requestId, @Nullable CharSequence message,
             @NonNull String servicePackageName) {
+        onFillRequestFailureOrTimeout(requestId, false, message, servicePackageName);
+    }
+
+    // FillServiceCallbacks
+    @Override
+    public void onFillRequestTimeout(int requestId, @NonNull String servicePackageName) {
+        onFillRequestFailureOrTimeout(requestId, true, null, servicePackageName);
+    }
+
+    private void onFillRequestFailureOrTimeout(int requestId, boolean timedOut,
+            @Nullable CharSequence message, @NonNull String servicePackageName) {
         synchronized (mLock) {
             if (mDestroyed) {
-                Slog.w(TAG, "Call to Session#onFillRequestFailure() rejected - session: "
-                        + id + " destroyed");
+                Slog.w(TAG, "Call to Session#onFillRequestFailureOrTimeout(req=" + requestId
+                        + ") rejected - session: " + id + " destroyed");
                 return;
             }
             mService.resetLastResponse();
+            final LogMaker requestLog = mRequestLogs.get(requestId);
+            if (requestLog == null) {
+                Slog.w(TAG, "onFillRequestFailureOrTimeout(): no log for id " + requestId);
+            } else {
+                requestLog.setType(timedOut ? MetricsEvent.TYPE_CLOSE : MetricsEvent.TYPE_FAILURE);
+            }
         }
-        LogMaker log = newLogMaker(MetricsEvent.AUTOFILL_REQUEST, servicePackageName)
-                .setType(MetricsEvent.TYPE_FAILURE);
-        mMetricsLogger.write(log);
-
-        getUiForShowing().showError(message, this);
+        if (message != null) {
+            getUiForShowing().showError(message, this);
+        }
         removeSelf();
     }
 
@@ -973,11 +1017,12 @@
                     + ", clientState=" + newClientState);
         }
         if (result instanceof FillResponse) {
-            writeLog(MetricsEvent.AUTOFILL_AUTHENTICATED);
+            logAuthenticationStatusLocked(requestId, MetricsEvent.AUTOFILL_AUTHENTICATED);
             replaceResponseLocked(authenticatedResponse, (FillResponse) result, newClientState);
         } else if (result instanceof Dataset) {
             if (datasetIdx != AutofillManager.AUTHENTICATION_ID_DATASET_ID_UNDEFINED) {
-                writeLog(MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
+                logAuthenticationStatusLocked(requestId,
+                        MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED);
                 if (newClientState != null) {
                     if (sDebug) Slog.d(TAG,  "Updating client state from auth dataset");
                     mClientState = newClientState;
@@ -986,13 +1031,15 @@
                 authenticatedResponse.getDatasets().set(datasetIdx, dataset);
                 autoFill(requestId, datasetIdx, dataset, false);
             } else {
-                writeLog(MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
+                logAuthenticationStatusLocked(requestId,
+                        MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION);
             }
         } else {
             if (result != null) {
                 Slog.w(TAG, "service returned invalid auth type: " + result);
             }
-            writeLog(MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
+            logAuthenticationStatusLocked(requestId,
+                    MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION);
             processNullResponseLocked(0);
         }
     }
@@ -1253,7 +1300,7 @@
             mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                     ignoredDatasets, changedFieldIds, changedDatasetIds,
                     manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                    mComponentName.getPackageName(), mCompatMode);
+                    mComponentName, mCompatMode);
         }
     }
 
@@ -1308,7 +1355,7 @@
                 mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                         ignoredDatasets, changedFieldIds, changedDatasetIds,
                         manuallyFilledFieldIds, manuallyFilledDatasetIds,
-                        mComponentName.getPackageName(), mCompatMode);
+                        mComponentName, mCompatMode);
                 return;
             }
             final Scores scores = result.getParcelable(EXTRA_SCORES);
@@ -1373,7 +1420,7 @@
             mService.logContextCommittedLocked(id, mClientState, mSelectedDatasetIds,
                     ignoredDatasets, changedFieldIds, changedDatasetIds, manuallyFilledFieldIds,
                     manuallyFilledDatasetIds, detectedFieldIds, detectedFieldClassifications,
-                    mComponentName.getPackageName(), mCompatMode);
+                    mComponentName, mCompatMode);
         });
 
         fcStrategy.getScores(callback, algorithm, algorithmArgs, currentValues, userValues);
@@ -1404,7 +1451,7 @@
          *   the current values of all fields in the screen.
          */
         if (saveInfo == null) {
-            if (sVerbose) Slog.w(TAG, "showSaveLocked(): no saveInfo from service");
+            if (sVerbose) Slog.v(TAG, "showSaveLocked(): no saveInfo from service");
             return true;
         }
 
@@ -1603,8 +1650,7 @@
                 mPendingSaveUi = new PendingUi(mActivityToken, id, client);
                 getUiForShowing().showSaveUi(mService.getServiceLabel(), mService.getServiceIcon(),
                         mService.getServicePackageName(), saveInfo, this,
-                        mComponentName.getPackageName(), this,
-                        mPendingSaveUi, mCompatMode);
+                        mComponentName, this, mPendingSaveUi, mCompatMode);
                 if (client != null) {
                     try {
                         client.setSaveUiState(id, true);
@@ -2065,7 +2111,7 @@
     }
 
     @Override
-    public void onFillReady(FillResponse response, AutofillId filledId,
+    public void onFillReady(@NonNull FillResponse response, @NonNull AutofillId filledId,
             @Nullable AutofillValue value) {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2081,8 +2127,8 @@
         }
 
         getUiForShowing().showFillUi(filledId, response, filterText,
-                mService.getServicePackageName(), mComponentName.getPackageName(),
-                mService.getServiceLabel(), mService.getServiceIcon(), this, mCompatMode);
+                mService.getServicePackageName(), mComponentName,
+                mService.getServiceLabel(), mService.getServiceIcon(), this, id, mCompatMode);
 
         synchronized (mLock) {
             if (mUiShownTime == 0) {
@@ -2103,9 +2149,8 @@
                 TimeUtils.formatDuration(duration, historyLog);
                 mUiLatencyHistory.log(historyLog.toString());
 
-                final LogMaker metricsLog = newLogMaker(MetricsEvent.AUTOFILL_UI_LATENCY)
-                        .addTaggedData(MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
-                mMetricsLogger.write(metricsLog);
+                addTaggedDataToRequestLogLocked(response.getRequestId(),
+                        MetricsEvent.FIELD_AUTOFILL_DURATION, duration);
             }
         }
     }
@@ -2474,6 +2519,14 @@
             TimeUtils.formatDuration(mUiShownTime - mStartTime, pw);
             pw.println();
         }
+        final int requestLogsSizes = mRequestLogs.size();
+        pw.print(prefix); pw.print("mSessionLogs: "); pw.println(requestLogsSizes);
+        for (int i = 0; i < requestLogsSizes; i++) {
+            final int requestId = mRequestLogs.keyAt(i);
+            final LogMaker log = mRequestLogs.valueAt(i);
+            pw.print(prefix2); pw.print('#'); pw.print(i); pw.print(": req=");
+            pw.print(requestId); pw.print(", log=" ); dumpRequestLog(pw, log); pw.println();
+        }
         pw.print(prefix); pw.print("mResponses: ");
         if (mResponses == null) {
             pw.println("null");
@@ -2532,6 +2585,56 @@
         mRemoteFillService.dump(prefix, pw);
     }
 
+    private static void dumpRequestLog(@NonNull PrintWriter pw, @NonNull LogMaker log) {
+        pw.print("CAT="); pw.print(log.getCategory());
+        pw.print(", TYPE=");
+        final int type = log.getType();
+        switch (type) {
+            case MetricsEvent.TYPE_SUCCESS: pw.print("SUCCESS"); break;
+            case MetricsEvent.TYPE_FAILURE: pw.print("FAILURE"); break;
+            case MetricsEvent.TYPE_CLOSE: pw.print("CLOSE"); break;
+            default: pw.print("UNSUPPORTED");
+        }
+        pw.print('('); pw.print(type); pw.print(')');
+        pw.print(", PKG="); pw.print(log.getPackageName());
+        pw.print(", SERVICE="); pw.print(log
+                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_SERVICE));
+        pw.print(", ORDINAL="); pw.print(log
+                .getTaggedData(MetricsEvent.FIELD_AUTOFILL_REQUEST_ORDINAL));
+        dumpNumericValue(pw, log, "FLAGS", MetricsEvent.FIELD_AUTOFILL_FLAGS);
+        dumpNumericValue(pw, log, "NUM_DATASETS", MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS);
+        dumpNumericValue(pw, log, "UI_LATENCY", MetricsEvent.FIELD_AUTOFILL_DURATION);
+        final int authStatus =
+                getNumericValue(log, MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS);
+        if (authStatus != 0) {
+            pw.print(", AUTH_STATUS=");
+            switch (authStatus) {
+                case MetricsEvent.AUTOFILL_AUTHENTICATED:
+                    pw.print("AUTHENTICATED"); break;
+                case MetricsEvent.AUTOFILL_DATASET_AUTHENTICATED:
+                    pw.print("DATASET_AUTHENTICATED"); break;
+                case MetricsEvent.AUTOFILL_INVALID_AUTHENTICATION:
+                    pw.print("INVALID_AUTHENTICATION"); break;
+                case MetricsEvent.AUTOFILL_INVALID_DATASET_AUTHENTICATION:
+                    pw.print("INVALID_DATASET_AUTHENTICATION"); break;
+                default: pw.print("UNSUPPORTED");
+            }
+            pw.print('('); pw.print(authStatus); pw.print(')');
+        }
+        dumpNumericValue(pw, log, "FC_IDS",
+                MetricsEvent.FIELD_AUTOFILL_NUM_FIELD_CLASSIFICATION_IDS);
+        dumpNumericValue(pw, log, "COMPAT_MODE",
+                MetricsEvent.FIELD_AUTOFILL_COMPAT_MODE);
+    }
+
+    private static void dumpNumericValue(@NonNull PrintWriter pw, @NonNull LogMaker log,
+            @NonNull String field, int tag) {
+        final int value = getNumericValue(log, tag);
+        if (value != 0) {
+            pw.print(", "); pw.print(field); pw.print('='); pw.print(value);
+        }
+    }
+
     void autoFillApp(Dataset dataset) {
         synchronized (mLock) {
             if (mDestroyed) {
@@ -2610,7 +2713,19 @@
         mUi.destroyAll(mPendingSaveUi, this, true);
         mUi.clearCallback(this);
         mDestroyed = true;
-        writeLog(MetricsEvent.AUTOFILL_SESSION_FINISHED);
+
+        // Log metrics
+        final int totalRequests = mRequestLogs.size();
+        if (totalRequests > 0) {
+            if (sVerbose) Slog.v(TAG, "destroyLocked(): logging " + totalRequests + " requests");
+            for (int i = 0; i < totalRequests; i++) {
+                final LogMaker log = mRequestLogs.valueAt(i);
+                mMetricsLogger.write(log);
+            }
+        }
+        mMetricsLogger.write(newLogMaker(MetricsEvent.AUTOFILL_SESSION_FINISHED)
+                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUMBER_REQUESTS, totalRequests));
+
         return mRemoteFillService;
     }
 
@@ -2719,14 +2834,36 @@
     }
 
     private LogMaker newLogMaker(int category, String servicePackageName) {
-        return Helper.newLogMaker(category, mComponentName.getPackageName(), servicePackageName,
-                mCompatMode);
+        return Helper.newLogMaker(category, mComponentName, servicePackageName, id, mCompatMode);
     }
 
     private void writeLog(int category) {
         mMetricsLogger.write(newLogMaker(category));
     }
 
+    private void logAuthenticationStatusLocked(int requestId, int status) {
+        addTaggedDataToRequestLogLocked(requestId,
+                MetricsEvent.FIELD_AUTOFILL_AUTHENTICATION_STATUS, status);
+    }
+
+    private void addTaggedDataToRequestLogLocked(int requestId, int tag, @Nullable Object value) {
+        final LogMaker requestLog = mRequestLogs.get(requestId);
+        if (requestLog == null) {
+            Slog.w(TAG,
+                    "addTaggedDataToRequestLogLocked(tag=" + tag + "): no log for id " + requestId);
+            return;
+        }
+        requestLog.addTaggedData(tag, value);
+    }
+
+    private static String requestLogToString(@NonNull LogMaker log) {
+        final StringWriter sw = new StringWriter();
+        final PrintWriter pw = new PrintWriter(sw);
+        dumpRequestLog(pw, log);
+        pw.flush();
+        return sw.toString();
+    }
+
     private void wtf(@Nullable Exception e, String fmt, Object...args) {
         final String message = String.format(fmt, args);
         mWtfHistory.log(message);
diff --git a/services/autofill/java/com/android/server/autofill/ViewState.java b/services/autofill/java/com/android/server/autofill/ViewState.java
index cff1a84..bb97e4a 100644
--- a/services/autofill/java/com/android/server/autofill/ViewState.java
+++ b/services/autofill/java/com/android/server/autofill/ViewState.java
@@ -19,6 +19,7 @@
 import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static com.android.server.autofill.Helper.sDebug;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.graphics.Rect;
 import android.service.autofill.FillResponse;
@@ -40,7 +41,7 @@
         /**
          * Called when the fill UI is ready to be shown for this view.
          */
-        void onFillReady(FillResponse fillResponse, AutofillId focusedId,
+        void onFillReady(@NonNull FillResponse fillResponse, @NonNull AutofillId focusedId,
                 @Nullable AutofillValue value);
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 811d87be..c5e838a 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -20,6 +20,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.IntentSender;
 import android.graphics.drawable.Drawable;
@@ -162,22 +163,25 @@
      * @param response the current fill response
      * @param filterText text of the view to be filled
      * @param servicePackageName package name of the autofill service filling the activity
-     * @param packageName package name of the activity that is filled
+     * @param componentName component name of the activity that is filled
      * @param serviceLabel label of autofill service
      * @param serviceIcon icon of autofill service
-     * @param callback Identifier for the caller
+     * @param callback identifier for the caller
+     * @param sessionId id of the autofill session
+     * @param compatMode whether the app is being autofilled in compatibility mode.
      */
     public void showFillUi(@NonNull AutofillId focusedId, @NonNull FillResponse response,
             @Nullable String filterText, @Nullable String servicePackageName,
-            @NonNull String packageName, @NonNull CharSequence serviceLabel,
-            @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback, boolean compatMode) {
+            @NonNull ComponentName componentName, @NonNull CharSequence serviceLabel,
+            @NonNull Drawable serviceIcon, @NonNull AutoFillUiCallback callback, int sessionId,
+            boolean compatMode) {
         if (sDebug) {
             final int size = filterText == null ? 0 : filterText.length();
             Slog.d(TAG, "showFillUi(): id=" + focusedId + ", filter=" + size + " chars");
         }
         final LogMaker log = Helper
-                .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, packageName, servicePackageName,
-                        compatMode)
+                .newLogMaker(MetricsEvent.AUTOFILL_FILL_UI, componentName, servicePackageName,
+                        sessionId, compatMode)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_FILTERTEXT_LEN,
                         filterText == null ? 0 : filterText.length())
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_DATASETS,
@@ -262,17 +266,19 @@
      */
     public void showSaveUi(@NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
             @Nullable String servicePackageName, @NonNull SaveInfo info,
-            @NonNull ValueFinder valueFinder, @NonNull String packageName,
+            @NonNull ValueFinder valueFinder, @NonNull ComponentName componentName,
             @NonNull AutoFillUiCallback callback, @NonNull PendingUi pendingSaveUi,
             boolean compatMode) {
-        if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
+        if (sVerbose) {
+            Slog.v(TAG, "showSaveUi() for " + componentName.toShortString() + ": " + info);
+        }
         int numIds = 0;
         numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
         numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
 
         final LogMaker log = Helper
-                .newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, packageName, servicePackageName,
-                        compatMode)
+                .newLogMaker(MetricsEvent.AUTOFILL_SAVE_UI, componentName, servicePackageName,
+                        pendingSaveUi.sessionId, compatMode)
                 .addTaggedData(MetricsEvent.FIELD_AUTOFILL_NUM_IDS, numIds);
 
         mHandler.post(() -> {
@@ -281,7 +287,7 @@
             }
             hideAllUiThread(callback);
             mSaveUi = new SaveUi(mContext, pendingSaveUi, serviceLabel, serviceIcon,
-                    servicePackageName, packageName, info, valueFinder, mOverlayControl,
+                    servicePackageName, componentName, info, valueFinder, mOverlayControl,
                     new SaveUi.OnSaveListener() {
                 @Override
                 public void onSave() {
@@ -409,7 +415,7 @@
         if (pendingSaveUi != null && notifyClient) {
             try {
                 if (sDebug) Slog.d(TAG, "destroySaveUiUiThread(): notifying client");
-                pendingSaveUi.client.setSaveUiState(pendingSaveUi.id, false);
+                pendingSaveUi.client.setSaveUiState(pendingSaveUi.sessionId, false);
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client to set save UI state to hidden: " + e);
             }
diff --git a/services/autofill/java/com/android/server/autofill/ui/PendingUi.java b/services/autofill/java/com/android/server/autofill/ui/PendingUi.java
index d1dfb5c..091208b 100644
--- a/services/autofill/java/com/android/server/autofill/ui/PendingUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/PendingUi.java
@@ -35,7 +35,7 @@
 
     private final IBinder mToken;
     private int mState;
-    public final int id;
+    public final int sessionId;
     public final IAutoFillManagerClient client;
 
     /**
@@ -43,10 +43,11 @@
      *
      * @param token token used to identify this pending UI.
      */
-    public PendingUi(@NonNull IBinder token, int id, @NonNull IAutoFillManagerClient client) {
+    public PendingUi(@NonNull IBinder token, int sessionId,
+            @NonNull IAutoFillManagerClient client) {
         mToken = token;
         mState = STATE_CREATED;
-        this.id = id;
+        this.sessionId = sessionId;
         this.client = client;
     }
 
@@ -81,7 +82,7 @@
 
     @Override
     public String toString() {
-        return "PendingUi: [token=" + mToken + ", id=" + id + ", state="
+        return "PendingUi: [token=" + mToken + ", sessionId=" + sessionId + ", state="
                 + DebugUtils.flagsToString(PendingUi.class, "STATE_", mState) + "]";
     }
 }
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index fa2a0d9..dc84498 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -23,6 +23,7 @@
 import android.annotation.Nullable;
 import android.app.Dialog;
 import android.app.PendingIntent;
+import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentSender;
@@ -53,7 +54,6 @@
 import android.view.autofill.AutofillManager;
 import android.widget.ImageView;
 import android.widget.RemoteViews;
-import android.widget.ScrollView;
 import android.widget.TextView;
 
 import com.android.internal.R;
@@ -134,14 +134,14 @@
     private final CharSequence mSubTitle;
     private final PendingUi mPendingUi;
     private final String mServicePackageName;
-    private final String mPackageName;
+    private final ComponentName mComponentName;
     private final boolean mCompatMode;
 
     private boolean mDestroyed;
 
     SaveUi(@NonNull Context context, @NonNull PendingUi pendingUi,
            @NonNull CharSequence serviceLabel, @NonNull Drawable serviceIcon,
-           @Nullable String servicePackageName, @NonNull String packageName,
+           @Nullable String servicePackageName, @NonNull ComponentName componentName,
            @NonNull SaveInfo info, @NonNull ValueFinder valueFinder,
            @NonNull OverlayControl overlayControl, @NonNull OnSaveListener listener,
            boolean compatMode) {
@@ -149,7 +149,7 @@
         mListener = new OneTimeListener(listener);
         mOverlayControl = overlayControl;
         mServicePackageName = servicePackageName;
-        mPackageName = packageName;
+        mComponentName = componentName;
         mCompatMode = compatMode;
 
         context = new ContextThemeWrapper(context, THEME_ID);
@@ -208,7 +208,7 @@
             mSubTitle = info.getDescription();
             if (mSubTitle != null) {
                 writeLog(MetricsEvent.AUTOFILL_SAVE_CUSTOM_SUBTITLE, type);
-                final ScrollView subtitleContainer =
+                final ViewGroup subtitleContainer =
                         view.findViewById(R.id.autofill_save_custom_subtitle);
                 final TextView subtitleView = new TextView(context);
                 subtitleView.setText(mSubTitle);
@@ -361,7 +361,7 @@
             }
 
             // Finally, add the custom description to the save UI.
-            final ScrollView subtitleContainer =
+            final ViewGroup subtitleContainer =
                     saveUiView.findViewById(R.id.autofill_save_custom_subtitle);
             subtitleContainer.addView(customSubtitleView);
             subtitleContainer.setVisibility(View.VISIBLE);
@@ -413,12 +413,12 @@
     }
 
     private LogMaker newLogMaker(int category, int saveType) {
-        return Helper.newLogMaker(category, mPackageName, mServicePackageName, mCompatMode)
-                .addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType);
+        return newLogMaker(category).addTaggedData(MetricsEvent.FIELD_AUTOFILL_SAVE_TYPE, saveType);
     }
 
     private LogMaker newLogMaker(int category) {
-        return Helper.newLogMaker(category, mPackageName, mServicePackageName, mCompatMode);
+        return Helper.newLogMaker(category, mComponentName, mServicePackageName,
+                mPendingUi.sessionId, mCompatMode);
     }
 
     private void writeLog(int category, int saveType) {
@@ -506,7 +506,7 @@
         pw.print(prefix); pw.print("subtitle: "); pw.println(mSubTitle);
         pw.print(prefix); pw.print("pendingUi: "); pw.println(mPendingUi);
         pw.print(prefix); pw.print("service: "); pw.println(mServicePackageName);
-        pw.print(prefix); pw.print("app: "); pw.println(mPackageName);
+        pw.print(prefix); pw.print("app: "); pw.println(mComponentName.toShortString());
         pw.print(prefix); pw.print("compat mode: "); pw.println(mCompatMode);
 
         final View view = mDialog.getWindow().getDecorView();
diff --git a/services/backup/java/com/android/server/backup/BackupManagerConstants.java b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
index dd6e6ab..ec21961 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerConstants.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerConstants.java
@@ -32,7 +32,7 @@
  * <p>The backup manager constants are encoded as a key value list separated by commas and stored as
  * a Settings.Secure.
  */
-class BackupManagerConstants extends KeyValueSettingObserver {
+public class BackupManagerConstants extends KeyValueSettingObserver {
     private static final String TAG = "BackupManagerConstants";
     private static final String SETTING = Settings.Secure.BACKUP_MANAGER_CONSTANTS;
 
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index bd51af2..cd1bd67 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -353,6 +353,11 @@
         mAlarmManager = alarmManager;
     }
 
+    @VisibleForTesting
+    void setPowerManager(PowerManager powerManager) {
+        mPowerManager = powerManager;
+    }
+
     public void setBackupManagerBinder(IBackupManager backupManagerBinder) {
         mBackupManagerBinder = backupManagerBinder;
     }
@@ -2410,25 +2415,30 @@
     public void backupNow() {
         mContext.enforceCallingOrSelfPermission(android.Manifest.permission.BACKUP, "backupNow");
 
-        final PowerSaveState result =
-                mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
-        if (result.batterySaverEnabled) {
-            if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode");
-            KeyValueBackupJob.schedule(mContext, mConstants);   // try again in several hours
-        } else {
-            if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
-            synchronized (mQueueLock) {
-                // Fire the intent that kicks off the whole shebang...
-                try {
-                    mRunBackupIntent.send();
-                } catch (PendingIntent.CanceledException e) {
-                    // should never happen
-                    Slog.e(TAG, "run-backup intent cancelled!");
-                }
+        long oldId = Binder.clearCallingIdentity();
+        try {
+            final PowerSaveState result =
+                    mPowerManager.getPowerSaveState(ServiceType.KEYVALUE_BACKUP);
+            if (result.batterySaverEnabled) {
+                if (DEBUG) Slog.v(TAG, "Not running backup while in battery save mode");
+                KeyValueBackupJob.schedule(mContext, mConstants);   // try again in several hours
+            } else {
+                if (DEBUG) Slog.v(TAG, "Scheduling immediate backup pass");
+                synchronized (mQueueLock) {
+                    // Fire the intent that kicks off the whole shebang...
+                    try {
+                        mRunBackupIntent.send();
+                    } catch (PendingIntent.CanceledException e) {
+                        // should never happen
+                        Slog.e(TAG, "run-backup intent cancelled!");
+                    }
 
-                // ...and cancel any pending scheduled job, because we've just superseded it
-                KeyValueBackupJob.cancel(mContext);
+                    // ...and cancel any pending scheduled job, because we've just superseded it
+                    KeyValueBackupJob.cancel(mContext);
+                }
             }
+        } finally {
+            Binder.restoreCallingIdentity(oldId);
         }
     }
 
@@ -2901,6 +2911,25 @@
         return currentTransport;
     }
 
+    /**
+     * Returns the {@link ComponentName} of the host service of the selected transport or {@code
+     * null} if no transport selected or if the transport selected is not registered.
+     */
+    @Override
+    @Nullable
+    public ComponentName getCurrentTransportComponent() {
+        mContext.enforceCallingOrSelfPermission(
+                android.Manifest.permission.BACKUP, "getCurrentTransportComponent");
+        long oldId = Binder.clearCallingIdentity();
+        try {
+            return mTransportManager.getCurrentTransportComponent();
+        } catch (TransportNotRegisteredException e) {
+            return null;
+        } finally {
+            Binder.restoreCallingIdentity(oldId);
+        }
+    }
+
     // Report all known, available backup transports
     @Override
     public String[] listAllTransports() {
diff --git a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
index aabe7f6..f2219a0 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerServiceInterface.java
@@ -16,6 +16,7 @@
 
 package com.android.server.backup;
 
+import android.annotation.Nullable;
 import android.app.IBackupAgent;
 import android.app.backup.IBackupManager;
 import android.app.backup.IBackupManagerMonitor;
@@ -132,6 +133,10 @@
   // Report the name of the currently active transport
   String getCurrentTransport();
 
+  // Report the component name of the host service of the currently active transport
+  @Nullable
+  ComponentName getCurrentTransportComponent();
+
   // Report all known, available backup transports
   String[] listAllTransports();
 
diff --git a/services/backup/java/com/android/server/backup/Trampoline.java b/services/backup/java/com/android/server/backup/Trampoline.java
index 2abeaa6..787d667 100644
--- a/services/backup/java/com/android/server/backup/Trampoline.java
+++ b/services/backup/java/com/android/server/backup/Trampoline.java
@@ -19,8 +19,8 @@
 import android.annotation.Nullable;
 import android.app.backup.BackupManager;
 import android.app.backup.IBackupManager;
-import android.app.backup.IBackupObserver;
 import android.app.backup.IBackupManagerMonitor;
+import android.app.backup.IBackupObserver;
 import android.app.backup.IFullBackupRestoreObserver;
 import android.app.backup.IRestoreSession;
 import android.app.backup.ISelectBackupTransportCallback;
@@ -341,6 +341,17 @@
         return (svc != null) ? svc.getCurrentTransport() : null;
     }
 
+    /**
+     * Returns the {@link ComponentName} of the host service of the selected transport or
+     * {@code null} if no transport selected or if the transport selected is not registered.
+     */
+    @Override
+    @Nullable
+    public ComponentName getCurrentTransportComponent() {
+        BackupManagerServiceInterface svc = mService;
+        return (svc != null) ? svc.getCurrentTransportComponent() : null;
+    }
+
     @Override
     public String[] listAllTransports() throws RemoteException {
         BackupManagerServiceInterface svc = mService;
diff --git a/services/backup/java/com/android/server/backup/TransportManager.java b/services/backup/java/com/android/server/backup/TransportManager.java
index 64e24d8..ddce6bb 100644
--- a/services/backup/java/com/android/server/backup/TransportManager.java
+++ b/services/backup/java/com/android/server/backup/TransportManager.java
@@ -176,12 +176,30 @@
         return mTransportWhitelist;
     }
 
+    /** Returns the name of the selected transport or {@code null} if no transport selected. */
     @Nullable
     public String getCurrentTransportName() {
         return mCurrentTransportName;
     }
 
     /**
+     * Returns the {@link ComponentName} of the host service of the selected transport or
+     * {@code null} if no transport selected.
+     *
+     * @throws TransportNotRegisteredException if the selected transport is not registered.
+     */
+    @Nullable
+    public ComponentName getCurrentTransportComponent()
+            throws TransportNotRegisteredException {
+        synchronized (mTransportLock) {
+            if (mCurrentTransportName == null) {
+                return null;
+            }
+            return getRegisteredTransportComponentOrThrowLocked(mCurrentTransportName);
+        }
+    }
+
+    /**
      * Returns the transport name associated with {@code transportComponent}.
      *
      * @throws TransportNotRegisteredException if the transport is not registered.
@@ -325,6 +343,16 @@
     }
 
     @GuardedBy("mTransportLock")
+    private ComponentName getRegisteredTransportComponentOrThrowLocked(String transportName)
+            throws TransportNotRegisteredException {
+        ComponentName transportComponent = getRegisteredTransportComponentLocked(transportName);
+        if (transportComponent == null) {
+            throw new TransportNotRegisteredException(transportName);
+        }
+        return transportComponent;
+    }
+
+    @GuardedBy("mTransportLock")
     private TransportDescription getRegisteredTransportDescriptionOrThrowLocked(
             ComponentName transportComponent) throws TransportNotRegisteredException {
         TransportDescription description =
diff --git a/services/core/java/com/android/server/AlarmManagerService.java b/services/core/java/com/android/server/AlarmManagerService.java
index 0775abf..99912d9 100644
--- a/services/core/java/com/android/server/AlarmManagerService.java
+++ b/services/core/java/com/android/server/AlarmManagerService.java
@@ -1388,7 +1388,19 @@
         }
 
         synchronized (mLock) {
-            return setKernelTime(mNativeData, millis) == 0;
+            final long currentTimeMillis = System.currentTimeMillis();
+            setKernelTime(mNativeData, millis);
+            final TimeZone timeZone = TimeZone.getDefault();
+            final int currentTzOffset = timeZone.getOffset(currentTimeMillis);
+            final int newTzOffset = timeZone.getOffset(millis);
+            if (currentTzOffset != newTzOffset) {
+                Slog.i(TAG, "Timezone offset has changed, updating kernel timezone");
+                setKernelTimezone(mNativeData, -(newTzOffset / 60000));
+            }
+            // The native implementation of setKernelTime can return -1 even when the kernel
+            // time was set correctly, so assume setting kernel time was successful and always
+            // return true.
+            return true;
         }
     }
 
@@ -1776,7 +1788,7 @@
             } else if (workSource == null && (callingUid < Process.FIRST_APPLICATION_UID
                     || UserHandle.isSameApp(callingUid, mSystemUiUid)
                     || ((mAppStateTracker != null)
-                        && mAppStateTracker.isUidPowerSaveWhitelisted(callingUid)))) {
+                        && mAppStateTracker.isUidPowerSaveUserWhitelisted(callingUid)))) {
                 flags |= AlarmManager.FLAG_ALLOW_WHILE_IDLE_UNRESTRICTED;
                 flags &= ~AlarmManager.FLAG_ALLOW_WHILE_IDLE;
             }
diff --git a/services/core/java/com/android/server/AppOpsService.java b/services/core/java/com/android/server/AppOpsService.java
index 3beebcb..aa86ea8 100644
--- a/services/core/java/com/android/server/AppOpsService.java
+++ b/services/core/java/com/android/server/AppOpsService.java
@@ -812,11 +812,12 @@
             resOps = new ArrayList<>();
             for (int j=0; j<pkgOps.size(); j++) {
                 Op curOp = pkgOps.valueAt(j);
-                long duration = curOp.duration == -1
+                final boolean running = curOp.duration == -1;
+                long duration = running
                         ? (elapsedNow - curOp.startRealtime)
                         : curOp.duration;
                 resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
-                        curOp.rejectTime, (int) duration, curOp.proxyUid,
+                        curOp.rejectTime, (int) duration, running, curOp.proxyUid,
                         curOp.proxyPackageName));
             }
         } else {
@@ -826,11 +827,12 @@
                     if (resOps == null) {
                         resOps = new ArrayList<>();
                     }
-                    long duration = curOp.duration == -1
+                    final boolean running = curOp.duration == -1;
+                    final long duration = running
                             ? (elapsedNow - curOp.startRealtime)
                             : curOp.duration;
                     resOps.add(new AppOpsManager.OpEntry(curOp.op, curOp.mode, curOp.time,
-                            curOp.rejectTime, (int) duration, curOp.proxyUid,
+                            curOp.rejectTime, (int) duration, running, curOp.proxyUid,
                             curOp.proxyPackageName));
                 }
             }
diff --git a/services/core/java/com/android/server/AppStateTracker.java b/services/core/java/com/android/server/AppStateTracker.java
index 9b001ce..3a7b5d6 100644
--- a/services/core/java/com/android/server/AppStateTracker.java
+++ b/services/core/java/com/android/server/AppStateTracker.java
@@ -117,6 +117,12 @@
     @GuardedBy("mLock")
     private int[] mPowerWhitelistedAllAppIds = new int[0];
 
+    /**
+     * User whitelisted apps in the device idle controller.
+     */
+    @GuardedBy("mLock")
+    private int[] mPowerWhitelistedUserAppIds = new int[0];
+
     @GuardedBy("mLock")
     private int[] mTempWhitelistedAppIds = mPowerWhitelistedAllAppIds;
 
@@ -983,13 +989,16 @@
      * Called by device idle controller to update the power save whitelists.
      */
     public void setPowerSaveWhitelistAppIds(
-            int[] powerSaveWhitelistAllAppIdArray, int[] tempWhitelistAppIdArray) {
+            int[] powerSaveWhitelistExceptIdleAppIdArray,
+            int[] powerSaveWhitelistUserAppIdArray,
+            int[] tempWhitelistAppIdArray) {
         synchronized (mLock) {
             final int[] previousWhitelist = mPowerWhitelistedAllAppIds;
             final int[] previousTempWhitelist = mTempWhitelistedAppIds;
 
-            mPowerWhitelistedAllAppIds = powerSaveWhitelistAllAppIdArray;
+            mPowerWhitelistedAllAppIds = powerSaveWhitelistExceptIdleAppIdArray;
             mTempWhitelistedAppIds = tempWhitelistAppIdArray;
+            mPowerWhitelistedUserAppIds = powerSaveWhitelistUserAppIdArray;
 
             if (isAnyAppIdUnwhitelisted(previousWhitelist, mPowerWhitelistedAllAppIds)) {
                 mHandler.notifyAllUnwhitelisted();
@@ -1194,6 +1203,16 @@
     }
 
     /**
+     * @param uid the uid to check for
+     * @return whether a UID is in the user defined power-save whitelist or not.
+     */
+    public boolean isUidPowerSaveUserWhitelisted(int uid) {
+        synchronized (mLock) {
+            return ArrayUtils.contains(mPowerWhitelistedUserAppIds, UserHandle.getAppId(uid));
+        }
+    }
+
+    /**
      * @return whether a UID is in the temp power-save whitelist or not.
      *
      * Note clients normally shouldn't need to access it. It's only for dumpsys.
@@ -1231,9 +1250,12 @@
             pw.print("Foreground uids: ");
             dumpUids(pw, mForegroundUids);
 
-            pw.print("Whitelist appids: ");
+            pw.print("Except-idle + user whitelist appids: ");
             pw.println(Arrays.toString(mPowerWhitelistedAllAppIds));
 
+            pw.print("User whitelist appids: ");
+            pw.println(Arrays.toString(mPowerWhitelistedUserAppIds));
+
             pw.print("Temp whitelist appids: ");
             pw.println(Arrays.toString(mTempWhitelistedAppIds));
 
@@ -1311,6 +1333,10 @@
                 proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
 
+            for (int appId : mPowerWhitelistedUserAppIds) {
+                proto.write(ForceAppStandbyTrackerProto.POWER_SAVE_USER_WHITELIST_APP_IDS, appId);
+            }
+
             for (int appId : mTempWhitelistedAppIds) {
                 proto.write(ForceAppStandbyTrackerProto.TEMP_POWER_SAVE_WHITELIST_APP_IDS, appId);
             }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index 0893c4b..c83080e 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.
@@ -4674,7 +4684,7 @@
     }
 
     private void updateLinkProperties(NetworkAgentInfo networkAgent, LinkProperties oldLp) {
-        LinkProperties newLp = networkAgent.linkProperties;
+        LinkProperties newLp = new LinkProperties(networkAgent.linkProperties);
         int netId = networkAgent.network.netId;
 
         // The NetworkAgentInfo does not know whether clatd is running on its network or not. Before
@@ -4708,6 +4718,9 @@
         }
         // TODO - move this check to cover the whole function
         if (!Objects.equals(newLp, oldLp)) {
+            synchronized (networkAgent) {
+                networkAgent.linkProperties = newLp;
+            }
             notifyIfacesChangedForNetworkStats();
             notifyNetworkCallbacks(networkAgent, ConnectivityManager.CALLBACK_IP_CHANGED);
         }
@@ -5618,6 +5631,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/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index 74b4543..0f4702c 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -1540,7 +1540,7 @@
 
                 mLocalActivityManager.registerScreenObserver(mScreenObserver);
 
-                passWhiteListToForceAppStandbyTrackerLocked();
+                passWhiteListsToForceAppStandbyTrackerLocked();
                 updateInteractivityLocked();
             }
             updateConnectivityState(null);
@@ -1631,7 +1631,7 @@
                             mPowerSaveWhitelistAppsExceptIdle, mPowerSaveWhitelistUserApps,
                             mPowerSaveWhitelistExceptIdleAppIds);
 
-                    passWhiteListToForceAppStandbyTrackerLocked();
+                    passWhiteListsToForceAppStandbyTrackerLocked();
                 }
                 return true;
             } catch (PackageManager.NameNotFoundException e) {
@@ -1650,7 +1650,7 @@
                         mPowerSaveWhitelistExceptIdleAppIds);
                 mPowerSaveWhitelistUserAppsExceptIdle.clear();
 
-                passWhiteListToForceAppStandbyTrackerLocked();
+                passWhiteListsToForceAppStandbyTrackerLocked();
             }
         }
     }
@@ -2589,7 +2589,7 @@
             }
             mLocalPowerManager.setDeviceIdleWhitelist(mPowerSaveWhitelistAllAppIdArray);
         }
-        passWhiteListToForceAppStandbyTrackerLocked();
+        passWhiteListsToForceAppStandbyTrackerLocked();
     }
 
     private void updateTempWhitelistAppIdsLocked(int appId, boolean adding) {
@@ -2615,7 +2615,7 @@
             }
             mLocalPowerManager.setDeviceIdleTempWhitelist(mTempWhitelistAppIdArray);
         }
-        passWhiteListToForceAppStandbyTrackerLocked();
+        passWhiteListsToForceAppStandbyTrackerLocked();
     }
 
     private void reportPowerSaveWhitelistChangedLocked() {
@@ -2630,9 +2630,10 @@
         getContext().sendBroadcastAsUser(intent, UserHandle.SYSTEM);
     }
 
-    private void passWhiteListToForceAppStandbyTrackerLocked() {
+    private void passWhiteListsToForceAppStandbyTrackerLocked() {
         mAppStateTracker.setPowerSaveWhitelistAppIds(
                 mPowerSaveWhitelistExceptIdleAppIdArray,
+                mPowerSaveWhitelistUserAppIdArray,
                 mTempWhitelistAppIdArray);
     }
 
diff --git a/services/core/java/com/android/server/PinnerService.java b/services/core/java/com/android/server/PinnerService.java
index 2869114..5a25f48 100644
--- a/services/core/java/com/android/server/PinnerService.java
+++ b/services/core/java/com/android/server/PinnerService.java
@@ -16,6 +16,8 @@
 
 package com.android.server;
 
+import android.annotation.Nullable;
+
 import android.content.BroadcastReceiver;
 import android.content.Context;
 import android.content.Intent;
@@ -47,10 +49,18 @@
 import dalvik.system.VMRuntime;
 
 import java.io.FileDescriptor;
+import java.io.Closeable;
+import java.io.InputStream;
+import java.io.DataInputStream;
 import java.io.IOException;
+import java.io.EOFException;
 import java.io.PrintWriter;
 import java.util.ArrayList;
 
+import java.util.zip.ZipFile;
+import java.util.zip.ZipException;
+import java.util.zip.ZipEntry;
+
 /**
  * <p>PinnerService pins important files for key processes in memory.</p>
  * <p>Files to pin are specified in the config_defaultPinnerServiceFiles
@@ -60,16 +70,18 @@
 public final class PinnerService extends SystemService {
     private static final boolean DEBUG = false;
     private static final String TAG = "PinnerService";
+    private static final int MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
+    private static final String PIN_META_FILENAME = "pinlist.meta";
+    private static final int PAGE_SIZE = (int) Os.sysconf(OsConstants._SC_PAGESIZE);
 
     private final Context mContext;
-    private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<PinnedFile>();
-    private final ArrayList<PinnedFile> mPinnedCameraFiles = new ArrayList<PinnedFile>();
     private final boolean mShouldPinCamera;
 
+    /* These lists protected by PinnerService monitor lock */
+    private final ArrayList<PinnedFile> mPinnedFiles = new ArrayList<PinnedFile>();
+    private final ArrayList<PinnedFile> mPinnedCameraFiles = new ArrayList<PinnedFile>();
+
     private BinderService mBinderService;
-
-    private final long MAX_CAMERA_PIN_SIZE = 80 * (1 << 20); //80MB max
-
     private PinnerHandler mPinnerHandler = null;
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
@@ -146,18 +158,18 @@
          // Files to pin come from the overlay and can be specified per-device config
         String[] filesToPin = mContext.getResources().getStringArray(
                 com.android.internal.R.array.config_defaultPinnerServiceFiles);
-        synchronized(this) {
-            // Continue trying to pin remaining files even if there is a failure
-            for (int i = 0; i < filesToPin.length; i++){
-                PinnedFile pf = pinFile(filesToPin[i], 0, 0, 0);
-                if (pf != null) {
-                    mPinnedFiles.add(pf);
-                    if (DEBUG) {
-                        Slog.i(TAG, "Pinned file = " + pf.mFilename);
-                    }
-                } else {
-                    Slog.e(TAG, "Failed to pin file = " + filesToPin[i]);
-                }
+        // Continue trying to pin each file even if we fail to pin some of them
+        for (String fileToPin : filesToPin) {
+            PinnedFile pf = pinFile(fileToPin,
+                                    Integer.MAX_VALUE,
+                                    /*attemptPinIntrospection=*/false);
+            if (pf == null) {
+                Slog.e(TAG, "Failed to pin file = " + fileToPin);
+                continue;
+            }
+
+            synchronized (this) {
+                mPinnedFiles.add(pf);
             }
         }
     }
@@ -166,44 +178,23 @@
      * Handler for camera pinning message
      */
     private void handlePinCamera(int userHandle) {
-        if (mShouldPinCamera) {
-            synchronized(this) {
-                boolean success = pinCamera(userHandle);
-                if (!success) {
-                    //this is not necessarily an error
-                    if (DEBUG) {
-                        Slog.v(TAG, "Failed to pin camera.");
-                    }
-                }
+        if (!mShouldPinCamera) return;
+        if (!pinCamera(userHandle)) {
+            if (DEBUG) {
+                Slog.v(TAG, "Failed to pin camera.");
             }
         }
     }
 
-    /**
-     *  determine if the camera app is already pinned by comparing the
-     *  intent resolution to the pinned files list
-     */
-    private boolean alreadyPinned(int userHandle) {
-        ApplicationInfo cameraInfo = getCameraInfo(userHandle);
-        if (cameraInfo == null ) {
-            return false;
-        }
-        for (int i = 0; i < mPinnedCameraFiles.size(); i++) {
-            if (mPinnedCameraFiles.get(i).mFilename.equals(cameraInfo.sourceDir)) {
-                if (DEBUG) {
-                  Slog.v(TAG, "Camera is already pinned");
-                }
-                return true;
-            }
-        }
-        return false;
-    }
-
     private void unpinCameraApp() {
-        for (int i = 0; i < mPinnedCameraFiles.size(); i++) {
-            unpinFile(mPinnedCameraFiles.get(i));
+        ArrayList<PinnedFile> pinnedCameraFiles;
+        synchronized (this) {
+            pinnedCameraFiles = new ArrayList<>(mPinnedCameraFiles);
+            mPinnedCameraFiles.clear();
         }
-        mPinnedCameraFiles.clear();
+        for (PinnedFile pinnedFile : pinnedCameraFiles) {
+            pinnedFile.close();
+        }
     }
 
     private boolean isResolverActivity(ActivityInfo info) {
@@ -255,15 +246,19 @@
 
         //pin APK
         String camAPK = cameraInfo.sourceDir;
-        PinnedFile pf = pinFile(camAPK, 0, 0, MAX_CAMERA_PIN_SIZE);
+        PinnedFile pf = pinFile(camAPK,
+                                MAX_CAMERA_PIN_SIZE,
+                                /*attemptPinIntrospection=*/true);
         if (pf == null) {
             Slog.e(TAG, "Failed to pin " + camAPK);
             return false;
         }
         if (DEBUG) {
-            Slog.i(TAG, "Pinned " + pf.mFilename);
+            Slog.i(TAG, "Pinned " + pf.fileName);
         }
-        mPinnedCameraFiles.add(pf);
+        synchronized (this) {
+            mPinnedCameraFiles.add(pf);
+        }
 
         // determine the ABI from either ApplicationInfo or Build
         String arch = "arm";
@@ -289,11 +284,13 @@
 
         //not pinning the oat/odex is not a fatal error
         for (String file : files) {
-            pf = pinFile(file, 0, 0, MAX_CAMERA_PIN_SIZE);
+            pf = pinFile(file, MAX_CAMERA_PIN_SIZE, /*attemptPinIntrospection=*/false);
             if (pf != null) {
-                mPinnedCameraFiles.add(pf);
+                synchronized (this) {
+                    mPinnedCameraFiles.add(pf);
+                }
                 if (DEBUG) {
-                    Slog.i(TAG, "Pinned " + pf.mFilename);
+                    Slog.i(TAG, "Pinned " + pf.fileName);
                 }
             }
         }
@@ -302,70 +299,294 @@
     }
 
 
-    /** mlock length bytes of fileToPin in memory, starting at offset
-     *  length == 0 means pin from offset to end of file
-     *  maxSize == 0 means infinite
+    /** mlock length bytes of fileToPin in memory
+     *
+     * If attemptPinIntrospection is true, then treat the file to pin as a zip file and
+     * look for a "pinlist.meta" file in the archive root directory. The structure of this
+     * file is a PINLIST_META as described below:
+     *
+     * <pre>
+     *   PINLIST_META: PIN_RANGE*
+     *   PIN_RANGE: PIN_START PIN_LENGTH
+     *   PIN_START: big endian i32: offset in bytes of pin region from file start
+     *   PIN_LENGTH: big endian i32: length of pin region in bytes
+     * </pre>
+     *
+     * (We use big endian because that's what DataInputStream is hardcoded to use.)
+     *
+     * If attemptPinIntrospection is false, then we use a single implicit PIN_RANGE of (0,
+     * maxBytesToPin); that is, we attempt to pin the first maxBytesToPin bytes of the file.
+     *
+     * After we open a file, we march through the list of pin ranges and attempt to pin
+     * each one, stopping after we've pinned maxBytesToPin bytes. (We may truncate the last
+     * pinned range to fit.)  In this way, by choosing to emit certain PIN_RANGE pairs
+     * before others, file generators can express pins in priority order, making most
+     * effective use of the pinned-page quota.
+     *
+     * N.B. Each PIN_RANGE is clamped to the actual bounds of the file; all inputs have a
+     * meaningful interpretation. Also, a range locking a single byte of a page locks the
+     * whole page. Any truncated PIN_RANGE at EOF is ignored. Overlapping pinned entries
+     * are legal, but each pin of a byte counts toward the pin quota regardless of whether
+     * that byte has already been pinned, so the generator of PINLIST_META ought to ensure
+     * that ranges are non-overlapping.
+     *
+     * @param fileToPin Path to file to pin
+     * @param maxBytesToPin Maximum number of bytes to pin
+     * @param attemptPinIntrospection If true, try to open file as a
+     *   zip in order to extract the
+     * @return Pinned memory resource owner thing or null on error
      */
-    private static PinnedFile pinFile(String fileToPin, long offset, long length, long maxSize) {
-        FileDescriptor fd = new FileDescriptor();
+    private static PinnedFile pinFile(String fileToPin,
+                                      int maxBytesToPin,
+                                      boolean attemptPinIntrospection) {
+        ZipFile fileAsZip = null;
+        InputStream pinRangeStream = null;
         try {
-            fd = Os.open(fileToPin,
-                    OsConstants.O_RDONLY | OsConstants.O_CLOEXEC | OsConstants.O_NOFOLLOW,
-                    OsConstants.O_RDONLY);
-
-            StructStat sb = Os.fstat(fd);
-
-            if (offset + length > sb.st_size) {
-                Os.close(fd);
-                Slog.e(TAG, "Failed to pin file " + fileToPin +
-                        ", request extends beyond end of file.  offset + length =  "
-                        + (offset + length) + ", file length = " + sb.st_size);
-                return null;
+            if (attemptPinIntrospection) {
+                fileAsZip = maybeOpenZip(fileToPin);
             }
 
-            if (length == 0) {
-                length = sb.st_size - offset;
+            if (fileAsZip != null) {
+                pinRangeStream = maybeOpenPinMetaInZip(fileAsZip, fileToPin);
             }
 
-            if (maxSize > 0 && length > maxSize) {
-                Slog.e(TAG, "Could not pin file " + fileToPin +
-                        ", size = " + length + ", maxSize = " + maxSize);
-                Os.close(fd);
-                return null;
-            }
+            Slog.d(TAG, "pinRangeStream: " + pinRangeStream);
 
-            long address = Os.mmap(0, length, OsConstants.PROT_READ,
-                    OsConstants.MAP_PRIVATE, fd, offset);
-            Os.close(fd);
-
-            Os.mlock(address, length);
-
-            return new PinnedFile(address, length, fileToPin);
-        } catch (ErrnoException e) {
-            Slog.e(TAG, "Could not pin file " + fileToPin + " with error " + e.getMessage());
-            if(fd.valid()) {
-                try {
-                    Os.close(fd);
-                }
-                catch (ErrnoException eClose) {
-                    Slog.e(TAG, "Failed to close fd, error = " + eClose.getMessage());
-                }
-            }
-            return null;
+            PinRangeSource pinRangeSource = (pinRangeStream != null)
+                ? new PinRangeSourceStream(pinRangeStream)
+                : new PinRangeSourceStatic(0, Integer.MAX_VALUE /* will be clipped */);
+            return pinFileRanges(fileToPin, maxBytesToPin, pinRangeSource);
+        } finally {
+            safeClose(pinRangeStream);
+            safeClose(fileAsZip);  // Also closes any streams we've opened
         }
     }
 
-    private static boolean unpinFile(PinnedFile pf) {
+    /**
+     * Attempt to open a file as a zip file. On any sort of corruption, log, swallow the
+     * error, and return null.
+     */
+    private static ZipFile maybeOpenZip(String fileName) {
+        ZipFile zip = null;
         try {
-            Os.munlock(pf.mAddress, pf.mLength);
-        } catch (ErrnoException e) {
-            Slog.e(TAG, "Failed to unpin file " + pf.mFilename + " with error " + e.getMessage());
-            return false;
+            zip = new ZipFile(fileName);
+        } catch (IOException ex) {
+            Slog.w(TAG,
+                   String.format(
+                       "could not open \"%s\" as zip: pinning as blob",
+                                 fileName),
+                   ex);
         }
-        if (DEBUG) {
-            Slog.i(TAG, "Unpinned file " + pf.mFilename );
+        return zip;
+    }
+
+    /**
+     * Open a pin metadata file in the zip if one is present.
+     *
+     * @param zipFile Zip file to search
+     * @return Open input stream or null on any error
+     */
+    private static InputStream maybeOpenPinMetaInZip(ZipFile zipFile, String fileName) {
+        ZipEntry pinMetaEntry = zipFile.getEntry(PIN_META_FILENAME);
+        InputStream pinMetaStream = null;
+        if (pinMetaEntry != null) {
+            try {
+                pinMetaStream = zipFile.getInputStream(pinMetaEntry);
+            } catch (IOException ex) {
+                Slog.w(TAG,
+                       String.format("error reading pin metadata \"%s\": pinning as blob",
+                                     fileName),
+                       ex);
+            }
         }
-        return true;
+        return pinMetaStream;
+    }
+
+    private static abstract class PinRangeSource {
+        /** Retrive a range to pin.
+         *
+         * @param outPinRange Receives the pin region
+         * @return True if we filled in outPinRange or false if we're out of pin entries
+         */
+        abstract boolean read(PinRange outPinRange);
+    }
+
+    private static final class PinRangeSourceStatic extends PinRangeSource {
+        private final int mPinStart;
+        private final int mPinLength;
+        private boolean mDone = false;
+
+        PinRangeSourceStatic(int pinStart, int pinLength) {
+            mPinStart = pinStart;
+            mPinLength = pinLength;
+        }
+
+        @Override
+        boolean read(PinRange outPinRange) {
+            outPinRange.start = mPinStart;
+            outPinRange.length = mPinLength;
+            boolean done = mDone;
+            mDone = true;
+            return !done;
+        }
+    }
+
+    private static final class PinRangeSourceStream extends PinRangeSource {
+        private final DataInputStream mStream;
+        private boolean mDone = false;
+
+        PinRangeSourceStream(InputStream stream) {
+            mStream = new DataInputStream(stream);
+        }
+
+        @Override
+        boolean read(PinRange outPinRange) {
+            if (!mDone) {
+                try {
+                    outPinRange.start = mStream.readInt();
+                    outPinRange.length = mStream.readInt();
+                } catch (IOException ex) {
+                    mDone = true;
+                }
+            }
+            return !mDone;
+        }
+    }
+
+    /**
+     * Helper for pinFile.
+     *
+     * @param fileToPin Name of file to pin
+     * @param maxBytesToPin Maximum number of bytes to pin
+     * @param pinRangeSource Read PIN_RANGE entries from this stream to tell us what bytes
+     *   to pin.
+     * @return PinnedFile or null on error
+     */
+    private static PinnedFile pinFileRanges(
+        String fileToPin,
+        int maxBytesToPin,
+        PinRangeSource pinRangeSource)
+    {
+        FileDescriptor fd = new FileDescriptor();
+        long address = -1;
+        int mapSize = 0;
+
+        try {
+            int openFlags = (OsConstants.O_RDONLY |
+                             OsConstants.O_CLOEXEC |
+                             OsConstants.O_NOFOLLOW);
+            fd = Os.open(fileToPin, openFlags, 0);
+            mapSize = (int) Math.min(Os.fstat(fd).st_size, Integer.MAX_VALUE);
+            address = Os.mmap(0, mapSize,
+                              OsConstants.PROT_READ,
+                              OsConstants.MAP_SHARED,
+                              fd, /*offset=*/0);
+
+            PinRange pinRange = new PinRange();
+            int bytesPinned = 0;
+
+            // We pin at page granularity, so make sure the limit is page-aligned
+            if (maxBytesToPin % PAGE_SIZE != 0) {
+                maxBytesToPin -= maxBytesToPin % PAGE_SIZE;
+            }
+
+            while (bytesPinned < maxBytesToPin && pinRangeSource.read(pinRange)) {
+                int pinStart = pinRange.start;
+                int pinLength = pinRange.length;
+                pinStart = clamp(0, pinStart, mapSize);
+                pinLength = clamp(0, pinLength, mapSize - pinStart);
+                pinLength = Math.min(maxBytesToPin - bytesPinned, pinLength);
+
+                // mlock doesn't require the region to be page-aligned, but we snap the
+                // lock region to page boundaries anyway so that we don't under-count
+                // locking a single byte of a page as a charge of one byte even though the
+                // OS will retain the whole page. Thanks to this adjustment, we slightly
+                // over-count the pin charge of back-to-back pins touching the same page,
+                // but better that than undercounting. Besides: nothing stops pin metafile
+                // creators from making the actual regions page-aligned.
+                pinLength += pinStart % PAGE_SIZE;
+                pinStart -= pinStart % PAGE_SIZE;
+                if (pinLength % PAGE_SIZE != 0) {
+                    pinLength += PAGE_SIZE - pinLength % PAGE_SIZE;
+                }
+                pinLength = clamp(0, pinLength, maxBytesToPin - bytesPinned);
+
+                if (pinLength > 0) {
+                    if (DEBUG) {
+                        Slog.d(TAG,
+                               String.format(
+                                   "pinning at %s %s bytes of %s",
+                                   pinStart, pinLength, fileToPin));
+                    }
+                    Os.mlock(address + pinStart, pinLength);
+                }
+                bytesPinned += pinLength;
+            }
+
+            PinnedFile pinnedFile = new PinnedFile(address, mapSize, fileToPin, bytesPinned);
+            address = -1;  // Ownership transferred
+            return pinnedFile;
+        } catch (ErrnoException ex) {
+            Slog.e(TAG, "Could not pin file " + fileToPin, ex);
+            return null;
+        } finally {
+            safeClose(fd);
+            if (address >= 0) {
+                safeMunmap(address, mapSize);
+            }
+        }
+    }
+
+    private static int clamp(int min, int value, int max) {
+        return Math.max(min, Math.min(value, max));
+    }
+
+    private static void safeMunmap(long address, long mapSize) {
+        try {
+            Os.munmap(address, mapSize);
+        } catch (ErrnoException ex) {
+            Slog.w(TAG, "ignoring error in unmap", ex);
+        }
+    }
+
+    /**
+     * Close FD, swallowing irrelevant errors.
+     */
+    private static void safeClose(@Nullable FileDescriptor fd) {
+        if (fd != null && fd.valid()) {
+            try {
+                Os.close(fd);
+            } catch (ErrnoException ex) {
+                // Swallow the exception: non-EBADF errors in close(2)
+                // indicate deferred paging write errors, which we
+                // don't care about here. The underlying file
+                // descriptor is always closed.
+                if (ex.errno == OsConstants.EBADF) {
+                    throw new AssertionError(ex);
+                }
+            }
+        }
+    }
+
+    /**
+     * Close closeable thing, swallowing errors.
+     */
+    private static void safeClose(@Nullable Closeable thing) {
+        if (thing != null) {
+            try {
+                thing.close();
+            } catch (IOException ex) {
+                Slog.w(TAG, "ignoring error closing resource: " + thing, ex);
+            }
+        }
+    }
+
+    private synchronized ArrayList<PinnedFile> snapshotPinnedFiles() {
+        int nrPinnedFiles = mPinnedFiles.size() + mPinnedCameraFiles.size();
+        ArrayList<PinnedFile> pinnedFiles = new ArrayList<>(nrPinnedFiles);
+        pinnedFiles.addAll(mPinnedFiles);
+        pinnedFiles.addAll(mPinnedCameraFiles);
+        return pinnedFiles;
     }
 
     private final class BinderService extends Binder {
@@ -373,31 +594,44 @@
         protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
             if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
             long totalSize = 0;
-            pw.println("Pinned Files:");
-            synchronized(this) {
-                for (int i = 0; i < mPinnedFiles.size(); i++) {
-                    pw.println(mPinnedFiles.get(i).mFilename);
-                    totalSize += mPinnedFiles.get(i).mLength;
-                }
-                for (int i = 0; i < mPinnedCameraFiles.size(); i++) {
-                    pw.println(mPinnedCameraFiles.get(i).mFilename);
-                    totalSize += mPinnedCameraFiles.get(i).mLength;
-                }
+            for (PinnedFile pinnedFile : snapshotPinnedFiles()) {
+                pw.format("%s %s\n", pinnedFile.fileName, pinnedFile.bytesPinned);
+                totalSize += pinnedFile.bytesPinned;
             }
-            pw.println("Total size: " + totalSize);
+            pw.format("Total size: %s\n", totalSize);
         }
     }
 
-    private static class PinnedFile {
-        long mAddress;
-        long mLength;
-        String mFilename;
+    private static final class PinnedFile implements AutoCloseable {
+        private long mAddress;
+        final int mapSize;
+        final String fileName;
+        final int bytesPinned;
 
-        PinnedFile(long address, long length, String filename) {
+        PinnedFile(long address, int mapSize, String fileName, int bytesPinned) {
              mAddress = address;
-             mLength = length;
-             mFilename = filename;
+             this.mapSize = mapSize;
+             this.fileName = fileName;
+             this.bytesPinned = bytesPinned;
         }
+
+        @Override
+        public void close() {
+            if (mAddress >= 0) {
+                safeMunmap(mAddress, mapSize);
+                mAddress = -1;
+            }
+        }
+
+        @Override
+        public void finalize() {
+            close();
+        }
+    }
+
+    final static class PinRange {
+        int start;
+        int length;
     }
 
     final class PinnerHandler extends Handler {
diff --git a/services/core/java/com/android/server/VibratorService.java b/services/core/java/com/android/server/VibratorService.java
index ede870f..95e5518 100644
--- a/services/core/java/com/android/server/VibratorService.java
+++ b/services/core/java/com/android/server/VibratorService.java
@@ -76,17 +76,35 @@
 
     private static final long[] DOUBLE_CLICK_EFFECT_FALLBACK_TIMINGS = { 0, 30, 100, 30 };
 
-    private static final float GAMMA_SCALE_FACTOR_MINIMUM = 2.0f;
-    private static final float GAMMA_SCALE_FACTOR_LOW = 1.5f;
-    private static final float GAMMA_SCALE_FACTOR_HIGH = 0.5f;
-    private static final float GAMMA_SCALE_FACTOR_NONE = 1.0f;
+    // Scale levels. Each level is defined as the delta between the current setting and the default
+    // intensity for that type of vibration (i.e. current - default).
+    private static final int SCALE_VERY_LOW = -2;
+    private static final int SCALE_LOW = -1;
+    private static final int SCALE_NONE = 0;
+    private static final int SCALE_HIGH = 1;
+    private static final int SCALE_VERY_HIGH = 2;
 
-    private static final int MAX_AMPLITUDE_MINIMUM_INTENSITY = 168; // 2/3 * 255
-    private static final int MAX_AMPLITUDE_LOW_INTENSITY = 192; // 3/4 * 255
+    // Gamma adjustments for scale levels.
+    private static final float SCALE_VERY_LOW_GAMMA = 2.0f;
+    private static final float SCALE_LOW_GAMMA = 1.5f;
+    private static final float SCALE_NONE_GAMMA = 1.0f;
+    private static final float SCALE_HIGH_GAMMA = 0.5f;
+    private static final float SCALE_VERY_HIGH_GAMMA = 0.25f;
+
+    // Max amplitudes for scale levels. If one is not listed, then the max amplitude is the default
+    // max amplitude.
+    private static final int SCALE_VERY_LOW_MAX_AMPLITUDE = 168; // 2/3 * 255
+    private static final int SCALE_LOW_MAX_AMPLITUDE = 192; // 3/4 * 255
 
     // If a vibration is playing for longer than 5s, it's probably not haptic feedback.
     private static final long MAX_HAPTIC_FEEDBACK_DURATION = 5000;
 
+
+    // A mapping from the intensity adjustment to the scaling to apply, where the intensity
+    // adjustment is defined as the delta between the default intensity level and the user selected
+    // intensity level. It's important that we apply the scaling on the delta between the two so
+    // that the default intensity level applies no scaling to application provided effects.
+    private final SparseArray<ScaleLevel> mScaleLevels;
     private final LinkedList<VibrationInfo> mPreviousVibrations;
     private final int mPreviousVibrationsLimit;
     private final boolean mAllowPriorityVibrationsInLowPowerMode;
@@ -180,6 +198,8 @@
                     case VibrationEffect.EFFECT_DOUBLE_CLICK:
                     case VibrationEffect.EFFECT_HEAVY_CLICK:
                     case VibrationEffect.EFFECT_TICK:
+                    case VibrationEffect.EFFECT_POP:
+                    case VibrationEffect.EFFECT_THUD:
                         return true;
                     default:
                         Slog.w(TAG, "Unknown prebaked vibration effect, "
@@ -254,6 +274,25 @@
         }
     }
 
+    private static final class ScaleLevel {
+        public final float gamma;
+        public final int maxAmplitude;
+
+        public ScaleLevel(float gamma) {
+            this(gamma, VibrationEffect.MAX_AMPLITUDE);
+        }
+
+        public ScaleLevel(float gamma, int maxAmplitude) {
+            this.gamma = gamma;
+            this.maxAmplitude = maxAmplitude;
+        }
+
+        @Override
+        public String toString() {
+            return "ScaleLevel{gamma=" + gamma + ", maxAmplitude=" + maxAmplitude + "}";
+        }
+    }
+
     VibratorService(Context context) {
         vibratorInit();
         // Reset the hardware to a default state, in case this is a runtime
@@ -295,11 +334,19 @@
         VibrationEffect tickEffect = createEffectFromResource(
                 com.android.internal.R.array.config_clockTickVibePattern);
 
-        mFallbackEffects = new SparseArray<VibrationEffect>();
+        mFallbackEffects = new SparseArray<>();
         mFallbackEffects.put(VibrationEffect.EFFECT_CLICK, clickEffect);
         mFallbackEffects.put(VibrationEffect.EFFECT_DOUBLE_CLICK, doubleClickEffect);
         mFallbackEffects.put(VibrationEffect.EFFECT_TICK, tickEffect);
         mFallbackEffects.put(VibrationEffect.EFFECT_HEAVY_CLICK, heavyClickEffect);
+
+        mScaleLevels = new SparseArray<>();
+        mScaleLevels.put(SCALE_VERY_LOW,
+                new ScaleLevel(SCALE_VERY_LOW_GAMMA, SCALE_VERY_LOW_MAX_AMPLITUDE));
+        mScaleLevels.put(SCALE_LOW, new ScaleLevel(SCALE_LOW_GAMMA, SCALE_LOW_MAX_AMPLITUDE));
+        mScaleLevels.put(SCALE_NONE, new ScaleLevel(SCALE_NONE_GAMMA));
+        mScaleLevels.put(SCALE_HIGH, new ScaleLevel(SCALE_HIGH_GAMMA));
+        mScaleLevels.put(SCALE_VERY_HIGH, new ScaleLevel(SCALE_VERY_HIGH_GAMMA));
     }
 
     private VibrationEffect createEffectFromResource(int resId) {
@@ -675,41 +722,35 @@
             return;
         }
 
-        final float gamma;
-        final int maxAmplitude;
+        final int defaultIntensity;
         if (vib.isNotification() || vib.isRingtone()) {
-            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
-                gamma = GAMMA_SCALE_FACTOR_MINIMUM;
-                maxAmplitude = MAX_AMPLITUDE_MINIMUM_INTENSITY;
-            } else if (intensity == Vibrator.VIBRATION_INTENSITY_MEDIUM) {
-                gamma = GAMMA_SCALE_FACTOR_LOW;
-                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
-            } else {
-                gamma = GAMMA_SCALE_FACTOR_NONE;
-                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
-            }
+            defaultIntensity = mVibrator.getDefaultNotificationVibrationIntensity();
+        } else if (vib.isHapticFeedback()) {
+            defaultIntensity = mVibrator.getDefaultHapticFeedbackIntensity();
         } else {
-            if (intensity == Vibrator.VIBRATION_INTENSITY_LOW) {
-                gamma = GAMMA_SCALE_FACTOR_LOW;
-                maxAmplitude = MAX_AMPLITUDE_LOW_INTENSITY;
-            } else if (intensity == Vibrator.VIBRATION_INTENSITY_HIGH) {
-                gamma = GAMMA_SCALE_FACTOR_HIGH;
-                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
-            } else {
-                gamma = GAMMA_SCALE_FACTOR_NONE;
-                maxAmplitude = VibrationEffect.MAX_AMPLITUDE;
-            }
+            // If we don't know what kind of vibration we're playing then just skip scaling for
+            // now.
+            return;
+        }
+
+        final ScaleLevel scale = mScaleLevels.get(intensity - defaultIntensity);
+        if (scale == null) {
+            // We should have scaling levels for all cases, so not being able to scale because of a
+            // missing level is unexpected.
+            Slog.e(TAG, "No configured scaling level!"
+                    + " (current=" + intensity + ", default= " + defaultIntensity + ")");
+            return;
         }
 
         VibrationEffect scaledEffect = null;
         if (vib.effect instanceof VibrationEffect.OneShot) {
             VibrationEffect.OneShot oneShot = (VibrationEffect.OneShot) vib.effect;
             oneShot = oneShot.resolve(mDefaultVibrationAmplitude);
-            scaledEffect = oneShot.scale(gamma, maxAmplitude);
+            scaledEffect = oneShot.scale(scale.gamma, scale.maxAmplitude);
         } else if (vib.effect instanceof VibrationEffect.Waveform) {
             VibrationEffect.Waveform waveform = (VibrationEffect.Waveform) vib.effect;
             waveform = waveform.resolve(mDefaultVibrationAmplitude);
-            scaledEffect = waveform.scale(gamma, maxAmplitude);
+            scaledEffect = waveform.scale(scale.gamma, scale.maxAmplitude);
         } else {
             Slog.w(TAG, "Unable to apply intensity scaling, unknown VibrationEffect type");
         }
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 4c2a940..ca715b5 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -119,7 +119,7 @@
 
     // How long the startForegroundService() grace period is to get around to
     // calling startForeground() before we ANR + stop it.
-    static final int SERVICE_START_FOREGROUND_TIMEOUT = 5*1000;
+    static final int SERVICE_START_FOREGROUND_TIMEOUT = 10*1000;
 
     final ActivityManagerService mAm;
 
@@ -501,6 +501,18 @@
             }
         }
 
+        // At this point we've applied allowed-to-start policy based on whether this was
+        // an ordinary startService() or a startForegroundService().  Now, only require that
+        // the app follow through on the startForegroundService() -> startForeground()
+        // contract if it actually targets O+.
+        if (r.appInfo.targetSdkVersion < Build.VERSION_CODES.O && fgRequired) {
+            if (DEBUG_BACKGROUND_CHECK || DEBUG_FOREGROUND_SERVICE) {
+                Slog.i(TAG, "startForegroundService() but host targets "
+                        + r.appInfo.targetSdkVersion + " - not requiring startForeground()");
+            }
+            fgRequired = false;
+        }
+
         NeededUriGrants neededGrants = mAm.checkGrantUriPermissionFromIntentLocked(
                 callingUid, r.packageName, service, service.getFlags(), null, r.userId);
 
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 7229ac1..9bc5829 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -37,9 +37,7 @@
 import static android.app.ActivityManagerInternal.ASSIST_KEY_RECEIVER_EXTRAS;
 import static android.app.ActivityManagerInternal.ASSIST_KEY_STRUCTURE;
 import static android.app.ActivityThread.PROC_START_SEQ_IDENT;
-import static android.app.AppOpsManager.OP_ASSIST_STRUCTURE;
 import static android.app.AppOpsManager.OP_NONE;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_HOME;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_UNDEFINED;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
@@ -5128,6 +5126,7 @@
         final ActivityRecord sourceRecord;
         final int targetUid;
         final String targetPackage;
+        final boolean isResolver;
         synchronized (this) {
             if (resultTo == null) {
                 throw new SecurityException("Must be called from an activity");
@@ -5165,6 +5164,7 @@
             }
             targetUid = sourceRecord.launchedFromUid;
             targetPackage = sourceRecord.launchedFromPackage;
+            isResolver = sourceRecord.isResolverOrChildActivity();
         }
 
         if (userId == UserHandle.USER_NULL) {
@@ -5184,6 +5184,7 @@
                     .setActivityOptions(bOptions)
                     .setMayWait(userId)
                     .setIgnoreTargetSecurity(ignoreTargetSecurity)
+                    .setFilterCallingUid(isResolver ? 0 /* system */ : targetUid)
                     .execute();
         } catch (SecurityException e) {
             // XXX need to figure out how to propagate to original app.
@@ -15175,6 +15176,7 @@
                         public void onLimitReached(int uid) {
                             Slog.wtf(TAG, "Uid " + uid + " sent too many Binders to uid "
                                     + Process.myUid());
+                            Binder.dumpProxyDebugInfo();
                             if (uid == Process.SYSTEM_UID) {
                                 Slog.i(TAG, "Skipping kill (uid is SYSTEM)");
                             } else {
@@ -15823,7 +15825,10 @@
     }
 
     @Override
-    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) {
+    public void getMyMemoryState(ActivityManager.RunningAppProcessInfo outState) {
+        if (outState == null) {
+            throw new IllegalArgumentException("outState is null");
+        }
         enforceNotIsolatedCaller("getMyMemoryState");
 
         final int callingUid = Binder.getCallingUid();
@@ -15834,7 +15839,9 @@
             synchronized (mPidsSelfLocked) {
                 proc = mPidsSelfLocked.get(Binder.getCallingPid());
             }
-            fillInProcMemInfo(proc, outInfo, clientTargetSdk);
+            if (proc != null) {
+                fillInProcMemInfo(proc, outState, clientTargetSdk);
+            }
         }
     }
 
@@ -20413,7 +20420,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/ActivityRecord.java b/services/core/java/com/android/server/am/ActivityRecord.java
index 73710d3..d456f62 100644
--- a/services/core/java/com/android/server/am/ActivityRecord.java
+++ b/services/core/java/com/android/server/am/ActivityRecord.java
@@ -115,6 +115,7 @@
 import static com.android.server.am.ActivityRecordProto.IDENTIFIER;
 import static com.android.server.am.ActivityRecordProto.PROC_ID;
 import static com.android.server.am.ActivityRecordProto.STATE;
+import static com.android.server.am.ActivityRecordProto.TRANSLUCENT;
 import static com.android.server.am.ActivityRecordProto.VISIBLE;
 import static com.android.server.policy.WindowManagerPolicy.NAV_BAR_LEFT;
 import static com.android.server.wm.IdentifierProto.HASH_CODE;
@@ -826,6 +827,18 @@
         return ResolverActivity.class.getName().equals(realActivity.getClassName());
     }
 
+    boolean isResolverOrChildActivity() {
+        if (!"android".equals(packageName)) {
+            return false;
+        }
+        try {
+            return ResolverActivity.class.isAssignableFrom(
+                    Object.class.getClassLoader().loadClass(realActivity.getClassName()));
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+    }
+
     ActivityRecord(ActivityManagerService _service, ProcessRecord _caller, int _launchedFromPid,
             int _launchedFromUid, String _launchedFromPackage, Intent _intent, String _resolvedType,
             ActivityInfo aInfo, Configuration _configuration,
@@ -1077,6 +1090,11 @@
             // System process can launch home activity.
             return true;
         }
+        // Allow the recents component to launch the home activity.
+        final RecentTasks recentTasks = mStackSupervisor.mService.getRecentTasks();
+        if (recentTasks != null && recentTasks.isCallerRecents(uid)) {
+            return true;
+        }
         // Resolver activity can launch home activity.
         return sourceRecord != null && sourceRecord.isResolverActivity();
     }
@@ -2395,11 +2413,16 @@
         }
 
         // Compute configuration based on max supported width and height.
-        outBounds.set(0, 0, maxActivityWidth, maxActivityHeight);
-        // Position the activity frame on the opposite side of the nav bar.
-        final int navBarPosition = service.mWindowManager.getNavBarPosition();
-        final int left = navBarPosition == NAV_BAR_LEFT ? appBounds.right - outBounds.width() : 0;
-        outBounds.offsetTo(left, 0 /* top */);
+        // Also account for the left / top insets (e.g. from display cutouts), which will be clipped
+        // away later in StackWindowController.adjustConfigurationForBounds(). Otherwise, the app
+        // bounds would end up too small.
+        outBounds.set(0, 0, maxActivityWidth + appBounds.left, maxActivityHeight + appBounds.top);
+
+        if (service.mWindowManager.getNavBarPosition() == NAV_BAR_LEFT) {
+            // Position the activity frame on the opposite side of the nav bar.
+            outBounds.left = appBounds.right - maxActivityWidth;
+            outBounds.right = appBounds.right;
+        }
     }
 
     boolean ensureActivityConfiguration(int globalChanges, boolean preserveWindow) {
@@ -2963,6 +2986,7 @@
         if (app != null) {
             proto.write(PROC_ID, app.pid);
         }
+        proto.write(TRANSLUCENT, !fullscreen);
         proto.end(token);
     }
 }
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/am/ActivityStartController.java b/services/core/java/com/android/server/am/ActivityStartController.java
index bbdc924..a7c3200 100644
--- a/services/core/java/com/android/server/am/ActivityStartController.java
+++ b/services/core/java/com/android/server/am/ActivityStartController.java
@@ -37,6 +37,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Slog;
 import android.view.RemoteAnimationAdapter;
@@ -340,7 +341,7 @@
                     // Collect information about the target of the Intent.
                     ActivityInfo aInfo = mSupervisor.resolveActivity(intent, resolvedTypes[i], 0,
                             null, userId, ActivityStarter.computeResolveFilterUid(
-                                    callingUid, realCallingUid));
+                                    callingUid, realCallingUid, UserHandle.USER_NULL));
                     // TODO: New, check if this is correct
                     aInfo = mService.getActivityInfoForUser(aInfo, userId);
 
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index ad434b4..73e3d33 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -312,6 +312,7 @@
         Configuration globalConfig;
         int userId;
         WaitResult waitResult;
+        int filterCallingUid;
 
         /**
          * If set to {@code true}, allows this activity start to look into
@@ -367,6 +368,7 @@
             mayWait = false;
             avoidMoveToFront = false;
             allowPendingRemoteAnimationRegistryLookup = true;
+            filterCallingUid = UserHandle.USER_NULL;
         }
 
         /**
@@ -404,6 +406,7 @@
             avoidMoveToFront = request.avoidMoveToFront;
             allowPendingRemoteAnimationRegistryLookup
                     = request.allowPendingRemoteAnimationRegistryLookup;
+            filterCallingUid = request.filterCallingUid;
         }
     }
 
@@ -792,7 +795,8 @@
                 callingPid = realCallingPid;
 
                 rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId, 0,
-                        computeResolveFilterUid(callingUid, realCallingUid));
+                        computeResolveFilterUid(
+                                callingUid, realCallingUid, mRequest.filterCallingUid));
                 aInfo = mSupervisor.resolveActivity(intent, rInfo, startFlags,
                         null /*profilerInfo*/);
 
@@ -984,7 +988,9 @@
         }
 
         ResolveInfo rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
-                0 /* matchFlags */, computeResolveFilterUid(callingUid, realCallingUid));
+                0 /* matchFlags */,
+                        computeResolveFilterUid(
+                                callingUid, realCallingUid, mRequest.filterCallingUid));
         if (rInfo == null) {
             UserInfo userInfo = mSupervisor.getUserInfo(userId);
             if (userInfo != null && userInfo.isManagedProfile()) {
@@ -1006,7 +1012,8 @@
                     rInfo = mSupervisor.resolveIntent(intent, resolvedType, userId,
                             PackageManager.MATCH_DIRECT_BOOT_AWARE
                                     | PackageManager.MATCH_DIRECT_BOOT_UNAWARE,
-                            computeResolveFilterUid(callingUid, realCallingUid));
+                            computeResolveFilterUid(
+                                    callingUid, realCallingUid, mRequest.filterCallingUid));
                 }
             }
         }
@@ -1078,8 +1085,8 @@
                         callingPid = Binder.getCallingPid();
                         componentSpecified = true;
                         rInfo = mSupervisor.resolveIntent(intent, null /*resolvedType*/, userId,
-                                0 /* matchFlags */, computeResolveFilterUid(callingUid,
-                                        realCallingUid));
+                                0 /* matchFlags */, computeResolveFilterUid(
+                                        callingUid, realCallingUid, mRequest.filterCallingUid));
                         aInfo = rInfo != null ? rInfo.activityInfo : null;
                         if (aInfo != null) {
                             aInfo = mService.getActivityInfoForUser(aInfo, userId);
@@ -1173,10 +1180,14 @@
      *
      * @param customCallingUid The UID on whose behalf to make the call.
      * @param actualCallingUid The UID actually making the call.
+     * @param filterCallingUid The UID to be used to filter for instant apps.
      * @return The logical UID making the call.
      */
-    static int computeResolveFilterUid(int customCallingUid, int actualCallingUid) {
-        return customCallingUid >= 0 ? customCallingUid : actualCallingUid;
+    static int computeResolveFilterUid(int customCallingUid, int actualCallingUid,
+            int filterCallingUid) {
+        return filterCallingUid != UserHandle.USER_NULL
+                ? filterCallingUid
+                : (customCallingUid >= 0 ? customCallingUid : actualCallingUid);
     }
 
     private int startActivity(final ActivityRecord r, ActivityRecord sourceRecord,
@@ -2562,6 +2573,11 @@
         return this;
     }
 
+    ActivityStarter setFilterCallingUid(int filterCallingUid) {
+        mRequest.filterCallingUid = filterCallingUid;
+        return this;
+    }
+
     ActivityStarter setComponentSpecified(boolean componentSpecified) {
         mRequest.componentSpecified = componentSpecified;
         return this;
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 89ea251..1c5dcce 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3312,6 +3312,9 @@
                 .append(Binder.getCallingPid()).toString();
 
         synchronized (mBluetoothA2dpEnabledLock) {
+            if (mBluetoothA2dpEnabled == on) {
+                return;
+            }
             mBluetoothA2dpEnabled = on;
             sendMsg(mAudioHandler, MSG_SET_FORCE_BT_A2DP_USE, SENDMSG_QUEUE,
                     AudioSystem.FOR_MEDIA,
@@ -3808,7 +3811,7 @@
                             queueMsgUnderWakeLock(mAudioHandler,
                                     MSG_SET_A2DP_SINK_CONNECTION_STATE,
                                     state,
-                                    0 /* arg2 unused */,
+                                    -1,
                                     btDevice,
                                     delay);
                         }
@@ -4654,22 +4657,22 @@
     public int setBluetoothA2dpDeviceConnectionState(BluetoothDevice device, int state, int profile)
     {
         return setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(
-                device, state, profile, false /* suppressNoisyIntent */);
+                device, state, profile, false /* suppressNoisyIntent */, -1 /* a2dpVolume */);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateSuppressNoisyIntent(BluetoothDevice device,
-                int state, int profile, boolean suppressNoisyIntent)
+                int state, int profile, boolean suppressNoisyIntent, int a2dpVolume)
     {
         if (mAudioHandler.hasMessages(MSG_SET_A2DP_SINK_CONNECTION_STATE, device)) {
             return 0;
         }
         return setBluetoothA2dpDeviceConnectionStateInt(
-                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE);
+                device, state, profile, suppressNoisyIntent, AudioSystem.DEVICE_NONE, a2dpVolume);
     }
 
     public int setBluetoothA2dpDeviceConnectionStateInt(
             BluetoothDevice device, int state, int profile, boolean suppressNoisyIntent,
-            int musicDevice)
+            int musicDevice, int a2dpVolume)
     {
         int delay;
         if (profile != BluetoothProfile.A2DP && profile != BluetoothProfile.A2DP_SINK) {
@@ -4687,7 +4690,7 @@
                     (profile == BluetoothProfile.A2DP ?
                         MSG_SET_A2DP_SINK_CONNECTION_STATE : MSG_SET_A2DP_SRC_CONNECTION_STATE),
                     state,
-                    0 /* arg2 unused */,
+                    a2dpVolume,
                     device,
                     delay);
         }
@@ -5217,41 +5220,41 @@
         }
     }
 
-    /** Handles internal volume messages in separate volume thread. */
-    private class AudioHandler extends Handler {
+    private void setDeviceVolume(VolumeStreamState streamState, int device) {
 
-        private void setDeviceVolume(VolumeStreamState streamState, int device) {
+        synchronized (VolumeStreamState.class) {
+            // Apply volume
+            streamState.applyDeviceVolume_syncVSS(device);
 
-            synchronized (VolumeStreamState.class) {
-                // Apply volume
-                streamState.applyDeviceVolume_syncVSS(device);
-
-                // Apply change to all streams using this one as alias
-                int numStreamTypes = AudioSystem.getNumStreamTypes();
-                for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
-                    if (streamType != streamState.mStreamType &&
-                            mStreamVolumeAlias[streamType] == streamState.mStreamType) {
-                        // Make sure volume is also maxed out on A2DP device for aliased stream
-                        // that may have a different device selected
-                        int streamDevice = getDeviceForStream(streamType);
-                        if ((device != streamDevice) && mAvrcpAbsVolSupported &&
-                                ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
-                            mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
-                        }
-                        mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
+            // Apply change to all streams using this one as alias
+            int numStreamTypes = AudioSystem.getNumStreamTypes();
+            for (int streamType = numStreamTypes - 1; streamType >= 0; streamType--) {
+                if (streamType != streamState.mStreamType &&
+                        mStreamVolumeAlias[streamType] == streamState.mStreamType) {
+                    // Make sure volume is also maxed out on A2DP device for aliased stream
+                    // that may have a different device selected
+                    int streamDevice = getDeviceForStream(streamType);
+                    if ((device != streamDevice) && mAvrcpAbsVolSupported &&
+                            ((device & AudioSystem.DEVICE_OUT_ALL_A2DP) != 0)) {
+                        mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                     }
+                    mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
                 }
             }
-            // Post a persist volume msg
-            sendMsg(mAudioHandler,
-                    MSG_PERSIST_VOLUME,
-                    SENDMSG_QUEUE,
-                    device,
-                    0,
-                    streamState,
-                    PERSIST_DELAY);
-
         }
+        // Post a persist volume msg
+        sendMsg(mAudioHandler,
+                MSG_PERSIST_VOLUME,
+                SENDMSG_QUEUE,
+                device,
+                0,
+                streamState,
+                PERSIST_DELAY);
+
+    }
+
+    /** Handles internal volume messages in separate volume thread. */
+    private class AudioHandler extends Handler {
 
         private void setAllVolumes(VolumeStreamState streamState) {
 
@@ -5618,7 +5621,7 @@
                     break;
 
                 case MSG_SET_A2DP_SINK_CONNECTION_STATE:
-                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1);
+                    onSetA2dpSinkConnectionState((BluetoothDevice)msg.obj, msg.arg1, msg.arg2);
                     mAudioEventWakeLock.release();
                     break;
 
@@ -5912,7 +5915,7 @@
         return mAudioHandler.hasMessages(MSG_BTA2DP_DOCK_TIMEOUT);
     }
 
-    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state)
+    private void onSetA2dpSinkConnectionState(BluetoothDevice btDevice, int state, int a2dpVolume)
     {
         if (DEBUG_DEVICES) {
             Log.d(TAG, "onSetA2dpSinkConnectionState btDevice=" + btDevice+"state=" + state);
@@ -5957,6 +5960,14 @@
                         makeA2dpDeviceUnavailableNow(mDockAddress);
                     }
                 }
+                if (a2dpVolume != -1) {
+                    VolumeStreamState streamState = mStreamStates[AudioSystem.STREAM_MUSIC];
+                    // Convert index to internal representation in VolumeStreamState
+                    a2dpVolume = a2dpVolume * 10;
+                    streamState.setIndex(a2dpVolume, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP,
+                            "onSetA2dpSinkConnectionState");
+                    setDeviceVolume(streamState, AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
+                }
                 makeA2dpDeviceAvailable(address, btDevice.getName(),
                         "onSetA2dpSinkConnectionState");
                 setCurrentAudioRouteName(btDevice.getAliasName());
@@ -6059,7 +6070,7 @@
                    // consistent with audio policy manager state
                    setBluetoothA2dpDeviceConnectionStateInt(
                            btDevice, BluetoothA2dp.STATE_DISCONNECTED, BluetoothProfile.A2DP,
-                           false /* suppressNoisyIntent */, musicDevice);
+                           false /* suppressNoisyIntent */, musicDevice, -1 /* a2dpVolume */);
                }
             }
         }
@@ -6069,6 +6080,9 @@
         // address is not used for now, but may be used when multiple a2dp devices are supported
         synchronized (mA2dpAvrcpLock) {
             mAvrcpAbsVolSupported = support;
+            sendMsg(mAudioHandler, MSG_SET_DEVICE_VOLUME, SENDMSG_QUEUE,
+                    AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP, 0,
+                    mStreamStates[AudioSystem.STREAM_MUSIC], 0);
         }
     }
 
diff --git a/services/core/java/com/android/server/connectivity/NetworkMonitor.java b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
index 4521d3a..9b9a380 100644
--- a/services/core/java/com/android/server/connectivity/NetworkMonitor.java
+++ b/services/core/java/com/android/server/connectivity/NetworkMonitor.java
@@ -19,7 +19,11 @@
 import static android.net.CaptivePortal.APP_RETURN_DISMISSED;
 import static android.net.CaptivePortal.APP_RETURN_UNWANTED;
 import static android.net.CaptivePortal.APP_RETURN_WANTED_AS_IS;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_PROBE_SPEC;
+import static android.net.ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL;
+import static android.net.metrics.ValidationProbeEvent.PROBE_FALLBACK;
 
+import android.annotation.Nullable;
 import android.app.PendingIntent;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -35,6 +39,7 @@
 import android.net.TrafficStats;
 import android.net.Uri;
 import android.net.captiveportal.CaptivePortalProbeResult;
+import android.net.captiveportal.CaptivePortalProbeSpec;
 import android.net.dns.ResolvUtil;
 import android.net.metrics.IpConnectivityLog;
 import android.net.metrics.NetworkEvent;
@@ -63,6 +68,7 @@
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.Protocol;
 import com.android.internal.util.State;
 import com.android.internal.util.StateMachine;
@@ -259,6 +265,8 @@
     private final URL mCaptivePortalHttpsUrl;
     private final URL mCaptivePortalHttpUrl;
     private final URL[] mCaptivePortalFallbackUrls;
+    @Nullable
+    private final CaptivePortalProbeSpec[] mCaptivePortalFallbackSpecs;
 
     @VisibleForTesting
     protected boolean mIsCaptivePortalCheckEnabled;
@@ -334,6 +342,7 @@
         mCaptivePortalHttpsUrl = makeURL(getCaptivePortalServerHttpsUrl());
         mCaptivePortalHttpUrl = makeURL(getCaptivePortalServerHttpUrl(settings, context));
         mCaptivePortalFallbackUrls = makeCaptivePortalFallbackUrls();
+        mCaptivePortalFallbackSpecs = makeCaptivePortalFallbackProbeSpecs();
 
         start();
     }
@@ -542,8 +551,12 @@
                                     sendMessage(CMD_CAPTIVE_PORTAL_APP_FINISHED, response);
                                 }
                             }));
-                    intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_URL,
-                            mLastPortalProbeResult.detectUrl);
+                    final CaptivePortalProbeResult probeRes = mLastPortalProbeResult;
+                    intent.putExtra(EXTRA_CAPTIVE_PORTAL_URL, probeRes.detectUrl);
+                    if (probeRes.probeSpec != null) {
+                        final String encodedSpec = probeRes.probeSpec.getEncodedSpec();
+                        intent.putExtra(EXTRA_CAPTIVE_PORTAL_PROBE_SPEC, encodedSpec);
+                    }
                     intent.putExtra(ConnectivityManager.EXTRA_CAPTIVE_PORTAL_USER_AGENT,
                             mCaptivePortalUserAgent);
                     intent.setFlags(
@@ -782,8 +795,9 @@
         private void resolveStrictModeHostname() {
             try {
                 // Do a blocking DNS resolution using the network-assigned nameservers.
+                // Do not set AI_ADDRCONFIG in ai_flags so we get all address families in advance.
                 final InetAddress[] ips = ResolvUtil.blockingResolveAllLocally(
-                        mNetwork, mPrivateDnsProviderHostname);
+                        mNetwork, mPrivateDnsProviderHostname, 0 /* aiFlags */);
                 mPrivateDnsConfig = new PrivateDnsConfig(mPrivateDnsProviderHostname, ips);
             } catch (UnknownHostException uhe) {
                 mPrivateDnsConfig = null;
@@ -882,23 +896,47 @@
     }
 
     private URL[] makeCaptivePortalFallbackUrls() {
-        String separator = ",";
-        String firstUrl = mSettings.getSetting(mContext,
-                Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
-        String joinedUrls = firstUrl + separator + mSettings.getSetting(mContext,
-                Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS, DEFAULT_OTHER_FALLBACK_URLS);
-        List<URL> urls = new ArrayList<>();
-        for (String s : joinedUrls.split(separator)) {
-            URL u = makeURL(s);
-            if (u == null) {
-                continue;
+        try {
+            String separator = ",";
+            String firstUrl = mSettings.getSetting(mContext,
+                    Settings.Global.CAPTIVE_PORTAL_FALLBACK_URL, DEFAULT_FALLBACK_URL);
+            String joinedUrls = firstUrl + separator + mSettings.getSetting(mContext,
+                    Settings.Global.CAPTIVE_PORTAL_OTHER_FALLBACK_URLS,
+                    DEFAULT_OTHER_FALLBACK_URLS);
+            List<URL> urls = new ArrayList<>();
+            for (String s : joinedUrls.split(separator)) {
+                URL u = makeURL(s);
+                if (u == null) {
+                    continue;
+                }
+                urls.add(u);
             }
-            urls.add(u);
+            if (urls.isEmpty()) {
+                Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
+            }
+            return urls.toArray(new URL[urls.size()]);
+        } catch (Exception e) {
+            // Don't let a misconfiguration bootloop the system.
+            Log.e(TAG, "Error parsing configured fallback URLs", e);
+            return new URL[0];
         }
-        if (urls.isEmpty()) {
-            Log.e(TAG, String.format("could not create any url from %s", joinedUrls));
+    }
+
+    private CaptivePortalProbeSpec[] makeCaptivePortalFallbackProbeSpecs() {
+        try {
+            final String settingsValue = mSettings.getSetting(
+                    mContext, Settings.Global.CAPTIVE_PORTAL_FALLBACK_PROBE_SPECS, null);
+            // Probe specs only used if configured in settings
+            if (TextUtils.isEmpty(settingsValue)) {
+                return null;
+            }
+
+            return CaptivePortalProbeSpec.parseCaptivePortalProbeSpecs(settingsValue);
+        } catch (Exception e) {
+            // Don't let a misconfiguration bootloop the system.
+            Log.e(TAG, "Error parsing configured fallback probe specs", e);
+            return null;
         }
-        return urls.toArray(new URL[urls.size()]);
     }
 
     private String getCaptivePortalUserAgent() {
@@ -915,6 +953,15 @@
         return mCaptivePortalFallbackUrls[idx];
     }
 
+    private CaptivePortalProbeSpec nextFallbackSpec() {
+        if (ArrayUtils.isEmpty(mCaptivePortalFallbackSpecs)) {
+            return null;
+        }
+        // Randomly change spec without memory. Also randomize the first attempt.
+        final int idx = Math.abs(new Random().nextInt()) % mCaptivePortalFallbackSpecs.length;
+        return mCaptivePortalFallbackSpecs[idx];
+    }
+
     @VisibleForTesting
     protected CaptivePortalProbeResult isCaptivePortal() {
         if (!mIsCaptivePortalCheckEnabled) {
@@ -985,7 +1032,7 @@
         // unnecessary resolution.
         final String host = (proxy != null) ? proxy.getHost() : url.getHost();
         sendDnsProbe(host);
-        return sendHttpProbe(url, probeType);
+        return sendHttpProbe(url, probeType, null);
     }
 
     /** Do a DNS resolution of the given server. */
@@ -1021,7 +1068,8 @@
      * @return a CaptivePortalProbeResult inferred from the HTTP response.
      */
     @VisibleForTesting
-    protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType) {
+    protected CaptivePortalProbeResult sendHttpProbe(URL url, int probeType,
+            @Nullable CaptivePortalProbeSpec probeSpec) {
         HttpURLConnection urlConnection = null;
         int httpResponseCode = CaptivePortalProbeResult.FAILED_CODE;
         String redirectUrl = null;
@@ -1093,7 +1141,12 @@
             TrafficStats.setThreadStatsTag(oldTag);
         }
         logValidationProbe(probeTimer.stop(), probeType, httpResponseCode);
-        return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
+
+        if (probeSpec == null) {
+            return new CaptivePortalProbeResult(httpResponseCode, redirectUrl, url.toString());
+        } else {
+            return probeSpec.getResult(httpResponseCode, redirectUrl);
+        }
     }
 
     private CaptivePortalProbeResult sendParallelHttpProbes(
@@ -1156,11 +1209,12 @@
         if (httpsResult.isPortal() || httpsResult.isSuccessful()) {
             return httpsResult;
         }
-        // If a fallback url exists, use a fallback probe to try again portal detection.
-        URL fallbackUrl = nextFallbackUrl();
+        // If a fallback method exists, use it to retry portal detection.
+        // If we have new-style probe specs, use those. Otherwise, use the fallback URLs.
+        final CaptivePortalProbeSpec probeSpec = nextFallbackSpec();
+        final URL fallbackUrl = (probeSpec != null) ? probeSpec.getUrl() : nextFallbackUrl();
         if (fallbackUrl != null) {
-            CaptivePortalProbeResult result =
-                    sendHttpProbe(fallbackUrl, ValidationProbeEvent.PROBE_FALLBACK);
+            CaptivePortalProbeResult result = sendHttpProbe(fallbackUrl, PROBE_FALLBACK, probeSpec);
             if (result.isPortal()) {
                 return result;
             }
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/display/ColorDisplayService.java b/services/core/java/com/android/server/display/ColorDisplayService.java
index 213ec36..0b6786c 100644
--- a/services/core/java/com/android/server/display/ColorDisplayService.java
+++ b/services/core/java/com/android/server/display/ColorDisplayService.java
@@ -189,6 +189,13 @@
         mController = new ColorDisplayController(getContext(), mCurrentUser);
         mController.setListener(this);
 
+        // Set the color mode, if valid, and immediately apply the updated tint matrix based on the
+        // existing activated state. This ensures consistency of tint across the color mode change.
+        onDisplayColorModeChanged(mController.getColorMode());
+
+        // Reset the activated state.
+        mIsActivated = null;
+
         setCoefficientMatrix(getContext(), DisplayTransformManager.needsLinearColorMatrix());
 
         // Prepare color transformation matrix.
@@ -201,9 +208,6 @@
         if (mIsActivated == null) {
             onActivated(mController.isActivated());
         }
-
-        // Transition the screen to the current temperature.
-        applyTint(false);
     }
 
     private void tearDown() {
@@ -223,8 +227,6 @@
             mColorMatrixAnimator.end();
             mColorMatrixAnimator = null;
         }
-
-        mIsActivated = null;
     }
 
     @Override
@@ -288,6 +290,10 @@
 
     @Override
     public void onDisplayColorModeChanged(int mode) {
+        if (mode == -1) {
+            return;
+        }
+
         // Cancel the night display tint animator if it's running.
         if (mColorMatrixAnimator != null) {
             mColorMatrixAnimator.cancel();
@@ -297,7 +303,8 @@
         setMatrix(mController.getColorTemperature(), mMatrixNight);
 
         final DisplayTransformManager dtm = getLocalService(DisplayTransformManager.class);
-        dtm.setColorMode(mode, mIsActivated ? mMatrixNight : MATRIX_IDENTITY);
+        dtm.setColorMode(mode, (mIsActivated != null && mIsActivated) ? mMatrixNight
+                : MATRIX_IDENTITY);
     }
 
     @Override
diff --git a/services/core/java/com/android/server/display/DisplayPowerController.java b/services/core/java/com/android/server/display/DisplayPowerController.java
index 3c66526..99412c5 100644
--- a/services/core/java/com/android/server/display/DisplayPowerController.java
+++ b/services/core/java/com/android/server/display/DisplayPowerController.java
@@ -489,6 +489,7 @@
         mTemporaryScreenBrightness = -1;
         mPendingScreenBrightnessSetting = -1;
         mTemporaryAutoBrightnessAdjustment = Float.NaN;
+        mPendingAutoBrightnessAdjustment = Float.NaN;
     }
 
     /**
@@ -1499,6 +1500,7 @@
             return false;
         }
         if (mAutoBrightnessAdjustment == mPendingAutoBrightnessAdjustment) {
+            mPendingAutoBrightnessAdjustment = Float.NaN;
             return false;
         }
         mAutoBrightnessAdjustment = mPendingAutoBrightnessAdjustment;
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
index 0cba76b..5681367 100755
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDevice.java
@@ -16,6 +16,7 @@
 
 package com.android.server.hdmi;
 
+import android.annotation.Nullable;
 import android.hardware.hdmi.HdmiDeviceInfo;
 import android.hardware.input.InputManager;
 import android.os.Handler;
@@ -31,6 +32,7 @@
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.hdmi.HdmiAnnotations.ServiceThreadOnly;
 
+import com.android.server.hdmi.HdmiControlService.SendMessageCallback;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
@@ -249,11 +251,11 @@
             case Constants.MESSAGE_SET_MENU_LANGUAGE:
                 return handleSetMenuLanguage(message);
             case Constants.MESSAGE_GIVE_PHYSICAL_ADDRESS:
-                return handleGivePhysicalAddress();
+                return handleGivePhysicalAddress(null);
             case Constants.MESSAGE_GIVE_OSD_NAME:
                 return handleGiveOsdName(message);
             case Constants.MESSAGE_GIVE_DEVICE_VENDOR_ID:
-                return handleGiveDeviceVendorId();
+                return handleGiveDeviceVendorId(null);
             case Constants.MESSAGE_GET_CEC_VERSION:
                 return handleGetCecVersion(message);
             case Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS:
@@ -325,23 +327,23 @@
     }
 
     @ServiceThreadOnly
-    protected boolean handleGivePhysicalAddress() {
+    protected boolean handleGivePhysicalAddress(@Nullable SendMessageCallback callback) {
         assertRunOnServiceThread();
 
         int physicalAddress = mService.getPhysicalAddress();
         HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildReportPhysicalAddressCommand(
                 mAddress, physicalAddress, mDeviceType);
-        mService.sendCecCommand(cecMessage);
+        mService.sendCecCommand(cecMessage, callback);
         return true;
     }
 
     @ServiceThreadOnly
-    protected boolean handleGiveDeviceVendorId() {
+    protected boolean handleGiveDeviceVendorId(@Nullable SendMessageCallback callback) {
         assertRunOnServiceThread();
         int vendorId = mService.getVendorId();
         HdmiCecMessage cecMessage = HdmiCecMessageBuilder.buildDeviceVendorIdCommand(
                 mAddress, vendorId);
-        mService.sendCecCommand(cecMessage);
+        mService.sendCecCommand(cecMessage, callback);
         return true;
     }
 
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
index 8c00be5..4ad51de 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecMessageValidator.java
@@ -22,7 +22,7 @@
 /**
  * A helper class to validates {@link HdmiCecMessage}.
  */
-public final class HdmiCecMessageValidator {
+public class HdmiCecMessageValidator {
     private static final String TAG = "HdmiCecMessageValidator";
 
     static final int OK = 0;
diff --git a/services/core/java/com/android/server/hdmi/HdmiControlService.java b/services/core/java/com/android/server/hdmi/HdmiControlService.java
index b06dba9..a1753e5 100644
--- a/services/core/java/com/android/server/hdmi/HdmiControlService.java
+++ b/services/core/java/com/android/server/hdmi/HdmiControlService.java
@@ -68,6 +68,7 @@
 import android.util.SparseArray;
 import android.util.SparseIntArray;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.DumpUtils;
 import com.android.internal.util.IndentingPrintWriter;
 import com.android.server.SystemService;
@@ -88,7 +89,7 @@
  * Provides a service for sending and processing HDMI control messages,
  * HDMI-CEC and MHL control command, and providing the information on both standard.
  */
-public final class HdmiControlService extends SystemService {
+public class HdmiControlService extends SystemService {
     private static final String TAG = "HdmiControlService";
     private final Locale HONG_KONG = new Locale("zh", "HK");
     private final Locale MACAU = new Locale("zh", "MO");
@@ -290,6 +291,9 @@
     @Nullable
     private PowerManager mPowerManager;
 
+    @Nullable
+    private Looper mIoLooper;
+
     // Last input port before switching to the MHL port. Should switch back to this port
     // when the mobile device sends the request one touch play with off.
     // Gets invalidated if we go to other port/input.
@@ -383,13 +387,18 @@
 
     @Override
     public void onStart() {
-        mIoThread.start();
+        if (mIoLooper == null) {
+            mIoThread.start();
+            mIoLooper = mIoThread.getLooper();
+        }
         mPowerStatus = HdmiControlManager.POWER_STATUS_TRANSIENT_TO_ON;
         mProhibitMode = false;
         mHdmiControlEnabled = readBooleanSetting(Global.HDMI_CONTROL_ENABLED, true);
         mMhlInputChangeEnabled = readBooleanSetting(Global.MHL_INPUT_SWITCHING_ENABLED, true);
 
-        mCecController = HdmiCecController.create(this);
+        if (mCecController == null) {
+            mCecController = HdmiCecController.create(this);
+        }
         if (mCecController != null) {
             if (mHdmiControlEnabled) {
                 initializeCec(INITIATED_BY_BOOT_UP);
@@ -406,7 +415,9 @@
         mMhlDevices = Collections.emptyList();
 
         initPortInfo();
-        mMessageValidator = new HdmiCecMessageValidator(this);
+        if (mMessageValidator == null) {
+            mMessageValidator = new HdmiCecMessageValidator(this);
+        }
         publishBinderService(Context.HDMI_CONTROL_SERVICE, new BinderService());
 
         if (mCecController != null) {
@@ -424,6 +435,11 @@
         mMhlController.setOption(OPTION_MHL_SERVICE_CONTROL, ENABLED);
     }
 
+    @VisibleForTesting
+    void setCecController(HdmiCecController cecController) {
+        mCecController = cecController;
+    }
+
     @Override
     public void onBootPhase(int phase) {
         if (phase == SystemService.PHASE_SYSTEM_SERVICES_READY) {
@@ -747,8 +763,19 @@
      *
      * <p>Declared as package-private.
      */
+    @Nullable
     Looper getIoLooper() {
-        return mIoThread.getLooper();
+        return mIoLooper;
+    }
+
+    @VisibleForTesting
+    void setIoLooper(Looper ioLooper) {
+        mIoLooper = ioLooper;
+    }
+
+    @VisibleForTesting
+    void setMessageValidator(HdmiCecMessageValidator messageValidator) {
+        mMessageValidator = messageValidator;
     }
 
     /**
diff --git a/services/core/java/com/android/server/location/GnssLocationProvider.java b/services/core/java/com/android/server/location/GnssLocationProvider.java
index b213ee60..b90c12a 100644
--- a/services/core/java/com/android/server/location/GnssLocationProvider.java
+++ b/services/core/java/com/android/server/location/GnssLocationProvider.java
@@ -1016,26 +1016,25 @@
             locationListener = mFusedLocationListener;
         }
 
-        if (!locationManager.isProviderEnabled(provider)) {
-            Log.w(TAG, "Unable to request location since " + provider
-                    + " provider does not exist or is not enabled.");
-            return;
-        }
-
         Log.i(TAG,
                 String.format(
                         "GNSS HAL Requesting location updates from %s provider for %d millis.",
                         provider, durationMillis));
-        locationManager.requestLocationUpdates(provider,
-                LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
-                locationListener, mHandler.getLooper());
-        locationListener.numLocationUpdateRequest++;
-        mHandler.postDelayed(() -> {
-            if (--locationListener.numLocationUpdateRequest == 0) {
-                Log.i(TAG, String.format("Removing location updates from %s provider.", provider));
-                locationManager.removeUpdates(locationListener);
-            }
-        }, durationMillis);
+        try {
+            locationManager.requestLocationUpdates(provider,
+                    LOCATION_UPDATE_MIN_TIME_INTERVAL_MILLIS, /*minDistance=*/ 0,
+                    locationListener, mHandler.getLooper());
+            locationListener.numLocationUpdateRequest++;
+            mHandler.postDelayed(() -> {
+                if (--locationListener.numLocationUpdateRequest == 0) {
+                    Log.i(TAG,
+                            String.format("Removing location updates from %s provider.", provider));
+                    locationManager.removeUpdates(locationListener);
+                }
+            }, durationMillis);
+        } catch (IllegalArgumentException e) {
+            Log.w(TAG, "Unable to request location.", e);
+        }
     }
 
     private void injectBestLocation(Location location) {
diff --git a/services/core/java/com/android/server/locksettings/LockSettingsService.java b/services/core/java/com/android/server/locksettings/LockSettingsService.java
index 1078f6e..36b04fc 100644
--- a/services/core/java/com/android/server/locksettings/LockSettingsService.java
+++ b/services/core/java/com/android/server/locksettings/LockSettingsService.java
@@ -2537,6 +2537,7 @@
      * Returns a fixed pseudorandom byte string derived from the user's synthetic password.
      * This is used to salt the password history hash to protect the hash against offline
      * bruteforcing, since rederiving this value requires a successful authentication.
+     * If user is a managed profile with unified challenge, currentCredential is ignored.
      */
     @Override
     public byte[] getHashFactor(String currentCredential, int userId) throws RemoteException {
@@ -2544,6 +2545,14 @@
         if (TextUtils.isEmpty(currentCredential)) {
             currentCredential = null;
         }
+        if (isManagedProfileWithUnifiedLock(userId)) {
+            try {
+                currentCredential = getDecryptedPasswordForTiedProfile(userId);
+            } catch (Exception e) {
+                Slog.e(TAG, "Failed to get work profile credential", e);
+                return null;
+            }
+        }
         synchronized (mSpManager) {
             if (!isSyntheticPasswordBasedCredentialLocked(userId)) {
                 Slog.w(TAG, "Synthetic password not enabled");
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 384efdd..a7df0e2 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -95,9 +95,8 @@
 
     // State guarded by mLock.
     private final Object mLock = new Object();
-    private final SparseArray<UserRecord> mUserRecords = new SparseArray<UserRecord>();
-    private final ArrayMap<IBinder, ClientRecord> mAllClientRecords =
-            new ArrayMap<IBinder, ClientRecord>();
+    private final SparseArray<UserRecord> mUserRecords = new SparseArray<>();
+    private final ArrayMap<IBinder, ClientRecord> mAllClientRecords = new ArrayMap<>();
     private int mCurrentUserId = -1;
     private final IAudioService mAudioService;
     private final AudioPlayerStateMonitor mAudioPlayerStateMonitor;
@@ -106,7 +105,7 @@
     private final IntArray mActivePlayerUidMinPriorityQueue = new IntArray();
 
     private final BroadcastReceiver mReceiver = new MediaRouterServiceBroadcastReceiver();
-    BluetoothDevice mBluetoothDevice;
+    BluetoothDevice mActiveBluetoothDevice;
     int mAudioRouteMainType = AudioRoutesInfo.MAIN_SPEAKER;
     boolean mGlobalBluetoothA2dpOn = false;
 
@@ -180,7 +179,8 @@
                                     | AudioRoutesInfo.MAIN_HEADPHONES
                                     | AudioRoutesInfo.MAIN_USB)) == 0) {
                                 // headset was plugged out.
-                                mGlobalBluetoothA2dpOn = mBluetoothDevice != null;
+                                mGlobalBluetoothA2dpOn = (newRoutes.bluetoothName != null
+                                        || mActiveBluetoothDevice != null);
                             } else {
                                 // headset was plugged in.
                                 mGlobalBluetoothA2dpOn = false;
@@ -197,7 +197,7 @@
             Slog.w(TAG, "RemoteException in the audio service.");
         }
 
-        IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED);
+        IntentFilter intentFilter = new IntentFilter(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED);
         context.registerReceiverAsUser(mReceiver, UserHandle.ALL, intentFilter, null, null);
     }
 
@@ -406,12 +406,14 @@
 
     void restoreBluetoothA2dp() {
         try {
-            boolean a2dpOn = false;
+            boolean a2dpOn;
+            BluetoothDevice btDevice;
             synchronized (mLock) {
                 a2dpOn = mGlobalBluetoothA2dpOn;
+                btDevice = mActiveBluetoothDevice;
             }
             // We don't need to change a2dp status when bluetooth is not connected.
-            if (mBluetoothDevice != null) {
+            if (btDevice != null) {
                 Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")");
                 mAudioService.setBluetoothA2dpOn(a2dpOn);
             }
@@ -653,17 +655,11 @@
     final class MediaRouterServiceBroadcastReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(Context context, Intent intent) {
-            if (intent.getAction().equals(BluetoothA2dp.ACTION_CONNECTION_STATE_CHANGED)) {
-                int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE,
-                        BluetoothProfile.STATE_DISCONNECTED);
-                if (state == BluetoothProfile.STATE_DISCONNECTED) {
-                    mGlobalBluetoothA2dpOn = false;
-                    mBluetoothDevice = null;
-                } else if (state == BluetoothProfile.STATE_CONNECTED) {
-                    mGlobalBluetoothA2dpOn = true;
-                    mBluetoothDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
-                    // To ensure that BT A2DP is on, call restoreBluetoothA2dp().
-                    restoreBluetoothA2dp();
+            if (intent.getAction().equals(BluetoothA2dp.ACTION_ACTIVE_DEVICE_CHANGED)) {
+                BluetoothDevice btDevice = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
+                synchronized (mLock) {
+                    mActiveBluetoothDevice = btDevice;
+                    mGlobalBluetoothA2dpOn = btDevice != null;
                 }
             }
         }
diff --git a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
index 5bd7c0b..ab482bb 100644
--- a/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
+++ b/services/core/java/com/android/server/net/NetworkPolicyManagerService.java
@@ -2706,6 +2706,9 @@
     private void normalizePoliciesNL(NetworkPolicy[] policies) {
         mNetworkPolicy.clear();
         for (NetworkPolicy policy : policies) {
+            if (policy == null) {
+                continue;
+            }
             // When two normalized templates conflict, prefer the most
             // restrictive policy
             policy.template = NetworkTemplate.normalize(policy.template, mMergedSubscriberIds);
diff --git a/services/core/java/com/android/server/net/NetworkStatsRecorder.java b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
index 4bee55e..a16dcf3 100644
--- a/services/core/java/com/android/server/net/NetworkStatsRecorder.java
+++ b/services/core/java/com/android/server/net/NetworkStatsRecorder.java
@@ -241,6 +241,20 @@
         NetworkStats.Entry entry = null;
         for (int i = 0; i < delta.size(); i++) {
             entry = delta.getValues(i, entry);
+
+            // As a last-ditch sanity check, report any negative values and
+            // clamp them so recording below doesn't croak.
+            if (entry.isNegative()) {
+                if (mObserver != null) {
+                    mObserver.foundNonMonotonic(delta, i, mCookie);
+                }
+                entry.rxBytes = Math.max(entry.rxBytes, 0);
+                entry.rxPackets = Math.max(entry.rxPackets, 0);
+                entry.txBytes = Math.max(entry.txBytes, 0);
+                entry.txPackets = Math.max(entry.txPackets, 0);
+                entry.operations = Math.max(entry.operations, 0);
+            }
+
             final NetworkIdentitySet ident = ifaceIdent.get(entry.iface);
             if (ident == null) {
                 unknownIfaces.add(entry.iface);
diff --git a/services/core/java/com/android/server/net/NetworkStatsService.java b/services/core/java/com/android/server/net/NetworkStatsService.java
index 3107241..aba75dd 100644
--- a/services/core/java/com/android/server/net/NetworkStatsService.java
+++ b/services/core/java/com/android/server/net/NetworkStatsService.java
@@ -1711,7 +1711,7 @@
         @Override
         public void foundNonMonotonic(NetworkStats left, int leftIndex, NetworkStats right,
                 int rightIndex, String cookie) {
-            Log.w(TAG, "found non-monotonic values; saving to dropbox");
+            Log.w(TAG, "Found non-monotonic values; saving to dropbox");
 
             // record error for debugging
             final StringBuilder builder = new StringBuilder();
@@ -1720,9 +1720,21 @@
             builder.append("left=").append(left).append('\n');
             builder.append("right=").append(right).append('\n');
 
-            final DropBoxManager dropBox = (DropBoxManager) mContext.getSystemService(
-                    Context.DROPBOX_SERVICE);
-            dropBox.addText(TAG_NETSTATS_ERROR, builder.toString());
+            mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
+                    builder.toString());
+        }
+
+        @Override
+        public void foundNonMonotonic(
+                NetworkStats stats, int statsIndex, String cookie) {
+            Log.w(TAG, "Found non-monotonic values; saving to dropbox");
+
+            final StringBuilder builder = new StringBuilder();
+            builder.append("Found non-monotonic " + cookie + " values at [" + statsIndex + "]\n");
+            builder.append("stats=").append(stats).append('\n');
+
+            mContext.getSystemService(DropBoxManager.class).addText(TAG_NETSTATS_ERROR,
+                    builder.toString());
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 8db676a..75592fb 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -822,6 +822,7 @@
                         }
                     }
                     r.setVisibility(true, nv.rank, nv.count);
+                    maybeRecordInterruptionLocked(r);
                     nv.recycle();
                 }
                 // Note that we might receive this event after notifications
@@ -1929,11 +1930,12 @@
 
     @GuardedBy("mNotificationLock")
     protected void maybeRecordInterruptionLocked(NotificationRecord r) {
-        if (r.isInterruptive()) {
+        if (r.isInterruptive() && !r.hasRecordedInterruption()) {
             mAppUsageStats.reportInterruptiveNotification(r.sbn.getPackageName(),
                     r.getChannel().getId(),
                     getRealUserId(r.sbn.getUserId()));
             logRecentLocked(r);
+            r.setRecordedInterruption(true);
         }
     }
 
@@ -2670,6 +2672,7 @@
                                 if (DBG) Slog.d(TAG, "Marking notification as seen " + keys[i]);
                                 reportSeen(r);
                                 r.setSeen();
+                                maybeRecordInterruptionLocked(r);
                             }
                         }
                     }
@@ -4441,7 +4444,7 @@
                     if (index < 0) {
                         mNotificationList.add(r);
                         mUsageStats.registerPostedByApp(r);
-                        r.setInterruptive(isVisuallyInterruptive(null, r));
+                        r.setInterruptive(true);
                     } else {
                         old = mNotificationList.get(index);
                         mNotificationList.set(index, r);
@@ -4450,7 +4453,7 @@
                         notification.flags |=
                                 old.getNotification().flags & FLAG_FOREGROUND_SERVICE;
                         r.isUpdate = true;
-                        r.setInterruptive(isVisuallyInterruptive(old, r));
+                        r.setTextChanged(isVisuallyInterruptive(old, r));
                     }
 
                     mNotificationsByKey.put(n.getKey(), r);
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 2aec3ea..0f3f44e 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -158,6 +158,8 @@
     private final NotificationStats mStats;
     private int mUserSentiment;
     private boolean mIsInterruptive;
+    private boolean mTextChanged;
+    private boolean mRecordedInterruption;
     private int mNumberOfSmartRepliesAdded;
     private boolean mHasSeenSmartReplies;
     /**
@@ -839,6 +841,9 @@
     /** Mark the notification as seen by the user. */
     public void setSeen() {
         mStats.setSeen();
+        if (mTextChanged) {
+            mIsInterruptive = true;
+        }
     }
 
     public void setAuthoritativeRank(int authoritativeRank) {
@@ -935,6 +940,18 @@
         mIsInterruptive = interruptive;
     }
 
+    public void setTextChanged(boolean textChanged) {
+        mTextChanged = textChanged;
+    }
+
+    public void setRecordedInterruption(boolean recorded) {
+        mRecordedInterruption = recorded;
+    }
+
+    public boolean hasRecordedInterruption() {
+        return mRecordedInterruption;
+    }
+
     public boolean isInterruptive() {
         return mIsInterruptive;
     }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index b05b900..ba73c7e 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -370,6 +370,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.
@@ -2075,6 +2076,16 @@
                             installerPackageName, null /*finishedReceiver*/,
                             updateUserIds, instantUserIds);
                 }
+                // if the required verifier is defined, but, is not the installer of record
+                // for the package, it gets notified
+                final boolean notifyVerifier = mRequiredVerifierPackage != null
+                        && !mRequiredVerifierPackage.equals(installerPackageName);
+                if (notifyVerifier) {
+                    sendPackageBroadcast(Intent.ACTION_PACKAGE_ADDED, packageName,
+                            extras, 0 /*flags*/,
+                            mRequiredVerifierPackage, null /*finishedReceiver*/,
+                            updateUserIds, instantUserIds);
+                }
 
                 // Send replaced for users that don't see the package for the first time
                 if (update) {
@@ -2088,6 +2099,12 @@
                                 installerPackageName, null /*finishedReceiver*/,
                                 updateUserIds, instantUserIds);
                     }
+                    if (notifyVerifier) {
+                        sendPackageBroadcast(Intent.ACTION_PACKAGE_REPLACED, packageName,
+                                extras, 0 /*flags*/,
+                                mRequiredVerifierPackage, null /*finishedReceiver*/,
+                                updateUserIds, instantUserIds);
+                    }
                     sendPackageBroadcast(Intent.ACTION_MY_PACKAGE_REPLACED,
                             null /*package*/, null /*extras*/, 0 /*flags*/,
                             packageName /*targetPackage*/,
@@ -8799,8 +8816,16 @@
 
         if (scanSystemPartition && isSystemPkgUpdated && !isSystemPkgBetter) {
             // The version of the application on the /system partition is less than or
-            // equal to the version on the /data partition. Throw an exception and use
-            // the application already installed on the /data partition.
+            // equal to the version on the /data partition. Even though the disabled system package
+            // is likely to be replaced by a version on the /data partition, we make assumptions
+            // that it's part of the mPackages collection during package manager initialization. So,
+            // add it to mPackages if there isn't already a package in the collection and then throw
+            // an exception to use the application already installed on the /data partition.
+            synchronized (mPackages) {
+                if (!mPackages.containsKey(pkg.packageName)) {
+                    mPackages.put(pkg.packageName, pkg);
+                }
+            }
             throw new PackageManagerException(Log.WARN, "Package " + pkg.packageName + " at "
                     + pkg.codePath + " ignored: updated version " + pkgSetting.versionCode
                     + " better than this " + pkg.getLongVersionCode());
@@ -13954,6 +13979,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);
@@ -14018,10 +14080,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);
@@ -14270,28 +14338,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);
         }
     }
 
@@ -17204,17 +17294,6 @@
                                         + "Persistent apps are not updateable.");
                         return;
                     }
-                    // Prevent apps from downgrading their targetSandbox.
-                    final int oldTargetSandbox = oldPackage.applicationInfo.targetSandboxVersion;
-                    final int newTargetSandbox = pkg.applicationInfo.targetSandboxVersion;
-                    if (oldTargetSandbox == 2 && newTargetSandbox != 2) {
-                        res.setError(PackageManager.INSTALL_FAILED_SANDBOX_VERSION_DOWNGRADE,
-                                "Package " + pkg.packageName + " new target sandbox "
-                                + newTargetSandbox + " is incompatible with the previous value of"
-                                + oldTargetSandbox + ".");
-                        return;
-                    }
-
                     // Prevent installing of child packages
                     if (oldPackage.parentPackage != null) {
                         res.setError(PackageManager.INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME,
@@ -23987,6 +24066,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
@@ -24418,6 +24509,9 @@
         if (info.targetSdkVersion < Build.VERSION_CODES.O) {
             return false;
         }
+        if (isInstantApp(packageName, userId)) {
+            return false;
+        }
         String appOpPermission = Manifest.permission.REQUEST_INSTALL_PACKAGES;
         String[] packagesDeclaringPermission = getAppOpPermissionPackages(appOpPermission);
         if (!ArrayUtils.contains(packagesDeclaringPermission, packageName)) {
diff --git a/services/core/java/com/android/server/pm/UserManagerService.java b/services/core/java/com/android/server/pm/UserManagerService.java
index 6005d61..407cb93 100644
--- a/services/core/java/com/android/server/pm/UserManagerService.java
+++ b/services/core/java/com/android/server/pm/UserManagerService.java
@@ -873,9 +873,8 @@
             throw new SecurityException("MANAGE_USERS permission is required to start intent "
                     + "after disabling quiet mode.");
         }
-        final boolean hasModifyQuietModePermission = ActivityManager.checkComponentPermission(
-                Manifest.permission.MODIFY_QUIET_MODE,
-                callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+        final boolean hasModifyQuietModePermission = hasPermissionGranted(
+                Manifest.permission.MODIFY_QUIET_MODE, callingUid);
         if (hasModifyQuietModePermission) {
             return;
         }
@@ -1002,6 +1001,30 @@
         }
     }
 
+    @Override
+    public void setUserAdmin(int userId) {
+        checkManageUserAndAcrossUsersFullPermission("set user admin");
+
+        synchronized (mPackagesLock) {
+            UserInfo info;
+            synchronized (mUsersLock) {
+                info = getUserInfoLU(userId);
+            }
+            if (info == null || info.isAdmin()) {
+                // Exit if no user found with that id, or the user is already an Admin.
+                return;
+            }
+
+            info.flags ^= UserInfo.FLAG_ADMIN;
+            writeUserLP(getUserDataLU(info.id));
+        }
+
+        // Remove non-admin restrictions.
+        // Keep synchronized with createUserEvenWhenDisallowed.
+        setUserRestriction(UserManager.DISALLOW_SMS, false, userId);
+        setUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS, false, userId);
+    }
+
     /**
      * Evicts a user's CE key by stopping and restarting the user.
      *
@@ -1122,8 +1145,8 @@
                 hasManageUsersPermission()) {
             return;
         }
-        if (ActivityManager.checkComponentPermission(Manifest.permission.INTERACT_ACROSS_USERS,
-                Binder.getCallingUid(), -1, true) != PackageManager.PERMISSION_GRANTED) {
+        if (!hasPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS,
+                Binder.getCallingUid())) {
             throw new SecurityException("You need INTERACT_ACROSS_USERS or MANAGE_USERS permission "
                     + "to: check " + name);
         }
@@ -1801,17 +1824,26 @@
      */
     private static final void checkManageUserAndAcrossUsersFullPermission(String message) {
         final int uid = Binder.getCallingUid();
-        if (uid != Process.SYSTEM_UID && uid != 0
-                && ActivityManager.checkComponentPermission(
-                Manifest.permission.MANAGE_USERS,
-                uid, -1, true) != PackageManager.PERMISSION_GRANTED
-                && ActivityManager.checkComponentPermission(
-                Manifest.permission.INTERACT_ACROSS_USERS_FULL,
-                uid, -1, true) != PackageManager.PERMISSION_GRANTED) {
-            throw new SecurityException(
-                    "You need MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permission to: "
-                            + message);
+
+        if (uid == Process.SYSTEM_UID || uid == 0) {
+            // System UID or root's UID are granted privilege.
+            return;
         }
+
+        if (hasPermissionGranted(Manifest.permission.MANAGE_USERS, uid)
+                && hasPermissionGranted(Manifest.permission.INTERACT_ACROSS_USERS_FULL, uid)) {
+            // Apps with both permissions are granted privilege.
+            return;
+        }
+
+        throw new SecurityException(
+                "You need MANAGE_USERS and INTERACT_ACROSS_USERS_FULL permission to: " + message);
+    }
+
+    private static boolean hasPermissionGranted(String permission, int uid) {
+        return ActivityManager.checkComponentPermission(
+                permission, uid, /* owningUid = */-1, /* exported = */ true) ==
+                PackageManager.PERMISSION_GRANTED;
     }
 
     /**
@@ -1872,9 +1904,7 @@
         final int callingUid = Binder.getCallingUid();
         return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
                 || callingUid == Process.ROOT_UID
-                || ActivityManager.checkComponentPermission(
-                        android.Manifest.permission.MANAGE_USERS,
-                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+                || hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid);
     }
 
     /**
@@ -1886,12 +1916,8 @@
         final int callingUid = Binder.getCallingUid();
         return UserHandle.isSameApp(callingUid, Process.SYSTEM_UID)
                 || callingUid == Process.ROOT_UID
-                || ActivityManager.checkComponentPermission(
-                        android.Manifest.permission.MANAGE_USERS,
-                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED
-                || ActivityManager.checkComponentPermission(
-                        android.Manifest.permission.CREATE_USERS,
-                        callingUid, -1, true) == PackageManager.PERMISSION_GRANTED;
+                || hasPermissionGranted(android.Manifest.permission.MANAGE_USERS, callingUid)
+                || hasPermissionGranted(android.Manifest.permission.CREATE_USERS, callingUid);
     }
 
     /**
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index c73ab75..781faa7 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -234,7 +234,6 @@
 import android.util.proto.ProtoOutputStream;
 import android.view.Display;
 import android.view.DisplayCutout;
-import android.view.DisplayInfo;
 import android.view.Gravity;
 import android.view.HapticFeedbackConstants;
 import android.view.IApplicationToken;
@@ -2292,6 +2291,11 @@
                     public void onTrustedChanged() {
                         mWindowManagerFuncs.notifyKeyguardTrustedChanged();
                     }
+
+                    @Override
+                    public void onShowingChanged() {
+                        mWindowManagerFuncs.onKeyguardShowingAndNotOccludedChanged();
+                    }
                 });
         mScreenshotHelper = new ScreenshotHelper(mContext);
     }
@@ -6149,7 +6153,9 @@
                     sendSystemKeyToStatusBarAsync(event.getKeyCode());
 
                     TelecomManager telecomManager = getTelecommService();
-                    if (telecomManager != null) {
+                    if (telecomManager != null && !mHandleVolumeKeysInWM) {
+                        // When {@link #mHandleVolumeKeysInWM} is set, volume key events
+                        // should be dispatched to WM.
                         if (telecomManager.isRinging()) {
                             // If an incoming call is ringing, either VOLUME key means
                             // "silence ringer".  We handle these keys here, rather than
@@ -6643,6 +6649,8 @@
     }
 
     void launchVoiceAssistWithWakeLock() {
+        sendCloseSystemWindows(SYSTEM_DIALOG_REASON_ASSIST);
+
         final Intent voiceIntent;
         if (!keyguardOn()) {
             voiceIntent = new Intent(RecognizerIntent.ACTION_WEB_SEARCH);
@@ -6916,7 +6924,7 @@
             } else {
                 if (DEBUG_WAKEUP) Slog.d(TAG,
                         "null mKeyguardDelegate: setting mKeyguardDrawComplete.");
-                finishKeyguardDrawn();
+                mHandler.sendEmptyMessage(MSG_KEYGUARD_DRAWN_COMPLETE);
             }
         }
     }
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index 89ae468..a1e54b6 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -653,6 +653,11 @@
          * abort animations that have no timeout, in case they got stuck.
          */
         void triggerAnimationFailsafe();
+
+        /**
+         * The keyguard showing state has changed
+         */
+        void onKeyguardShowingAndNotOccludedChanged();
     }
 
     /** Window has been added to the screen. */
diff --git a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
index e56caf8..1cba1c7 100644
--- a/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
+++ b/services/core/java/com/android/server/policy/keyguard/KeyguardStateMonitor.java
@@ -94,6 +94,7 @@
     public void onShowingStateChanged(boolean showing) {
         mIsShowing = showing;
 
+        mCallback.onShowingChanged();
         try {
             mKeystoreService.onKeyguardVisibilityChanged(showing, mCurrentUserId);
         } catch (RemoteException e) {
@@ -132,6 +133,7 @@
 
     public interface StateCallback {
         void onTrustedChanged();
+        void onShowingChanged();
     }
 
     public void dump(String prefix, PrintWriter pw) {
diff --git a/services/core/java/com/android/server/power/BatterySaverPolicy.java b/services/core/java/com/android/server/power/BatterySaverPolicy.java
index 91ef3d4..ed2b79e 100644
--- a/services/core/java/com/android/server/power/BatterySaverPolicy.java
+++ b/services/core/java/com/android/server/power/BatterySaverPolicy.java
@@ -392,7 +392,7 @@
         mForceBackgroundCheck = parser.getBoolean(KEY_FORCE_BACKGROUND_CHECK, true);
         mOptionalSensorsDisabled = parser.getBoolean(KEY_OPTIONAL_SENSORS_DISABLED, true);
         mAodDisabled = parser.getBoolean(KEY_AOD_DISABLED, true);
-        mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, true);
+        mSendTronLog = parser.getBoolean(KEY_SEND_TRON_LOG, false);
 
         // Get default value from Settings.Secure
         final int defaultGpsMode = Settings.Secure.getInt(mContentResolver, SECURE_KEY_GPS_MODE,
diff --git a/services/core/java/com/android/server/slice/SliceManagerService.java b/services/core/java/com/android/server/slice/SliceManagerService.java
index 2621c50..c3b9841 100644
--- a/services/core/java/com/android/server/slice/SliceManagerService.java
+++ b/services/core/java/com/android/server/slice/SliceManagerService.java
@@ -55,6 +55,7 @@
 import android.os.UserHandle;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseArray;
 import android.util.Xml.Encoding;
 
 import com.android.internal.annotations.GuardedBy;
@@ -77,6 +78,7 @@
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Objects;
+import java.util.function.Supplier;
 
 public class SliceManagerService extends ISliceManager.Stub {
 
@@ -90,6 +92,10 @@
 
     @GuardedBy("mLock")
     private final ArrayMap<Uri, PinnedSliceState> mPinnedSlicesByUri = new ArrayMap<>();
+    @GuardedBy("mLock")
+    private final SparseArray<PackageMatchingCache> mAssistantLookup = new SparseArray<>();
+    @GuardedBy("mLock")
+    private final SparseArray<PackageMatchingCache> mHomeLookup = new SparseArray<>();
     private final Handler mHandler;
 
     private final SlicePermissionManager mPermissions;
@@ -453,17 +459,37 @@
     }
 
     private boolean isAssistant(String pkg, int userId) {
-        final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
-        if (cn == null) {
-            return false;
-        }
-        return cn.getPackageName().equals(pkg);
+        return getAssistantMatcher(userId).matches(pkg);
     }
 
     private boolean isDefaultHomeApp(String pkg, int userId) {
-        String defaultHome = getDefaultHome(userId);
+        return getHomeMatcher(userId).matches(pkg);
+    }
 
-        return pkg != null && Objects.equals(pkg, defaultHome);
+    private PackageMatchingCache getAssistantMatcher(int userId) {
+        PackageMatchingCache matcher = mAssistantLookup.get(userId);
+        if (matcher == null) {
+            matcher = new PackageMatchingCache(() -> getAssistant(userId));
+            mAssistantLookup.put(userId, matcher);
+        }
+        return matcher;
+    }
+
+    private PackageMatchingCache getHomeMatcher(int userId) {
+        PackageMatchingCache matcher = mHomeLookup.get(userId);
+        if (matcher == null) {
+            matcher = new PackageMatchingCache(() -> getDefaultHome(userId));
+            mHomeLookup.put(userId, matcher);
+        }
+        return matcher;
+    }
+
+    private String getAssistant(int userId) {
+        final ComponentName cn = mAssistUtils.getAssistComponentForUser(userId);
+        if (cn == null) {
+            return null;
+        }
+        return cn.getPackageName();
     }
 
     // Based on getDefaultHome in ShortcutService.
@@ -559,6 +585,30 @@
         return mPermissions.getAllPackagesGranted(pkg);
     }
 
+    /**
+     * Holder that caches a package that has access to a slice.
+     */
+    static class PackageMatchingCache {
+
+        private final Supplier<String> mPkgSource;
+        private String mCurrentPkg;
+
+        public PackageMatchingCache(Supplier<String> pkgSource) {
+            mPkgSource = pkgSource;
+        }
+
+        public boolean matches(String pkgCandidate) {
+            if (pkgCandidate == null) return false;
+
+            if (Objects.equals(pkgCandidate, mCurrentPkg)) {
+                return true;
+            }
+            // Failed on cached value, try updating.
+            mCurrentPkg = mPkgSource.get();
+            return Objects.equals(pkgCandidate, mCurrentPkg);
+        }
+    }
+
     public static class Lifecycle extends SystemService {
         private SliceManagerService mService;
 
diff --git a/services/core/java/com/android/server/stats/StatsCompanionService.java b/services/core/java/com/android/server/stats/StatsCompanionService.java
index 3798416..4d65440 100644
--- a/services/core/java/com/android/server/stats/StatsCompanionService.java
+++ b/services/core/java/com/android/server/stats/StatsCompanionService.java
@@ -18,6 +18,7 @@
 import android.annotation.Nullable;
 import android.app.ActivityManagerInternal;
 import android.app.AlarmManager;
+import android.app.AlarmManager.OnAlarmListener;
 import android.app.PendingIntent;
 import android.app.ProcessMemoryState;
 import android.app.StatsManager;
@@ -124,9 +125,9 @@
     private static IStatsManager sStatsd;
     private static final Object sStatsdLock = new Object();
 
-    private final PendingIntent mAnomalyAlarmIntent;
-    private final PendingIntent mPullingAlarmIntent;
-    private final PendingIntent mPeriodicAlarmIntent;
+    private final OnAlarmListener mAnomalyAlarmListener = new AnomalyAlarmListener();
+    private final OnAlarmListener mPullingAlarmListener = new PullingAlarmListener();
+    private final OnAlarmListener mPeriodicAlarmListener = new PeriodicAlarmListener();
     private final BroadcastReceiver mAppUpdateReceiver;
     private final BroadcastReceiver mUserUpdateReceiver;
     private final ShutdownEventReceiver mShutdownEventReceiver;
@@ -158,12 +159,6 @@
         mContext = context;
         mAlarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE);
 
-        mAnomalyAlarmIntent = PendingIntent.getBroadcast(mContext, 0,
-                new Intent(mContext, AnomalyAlarmReceiver.class), 0);
-        mPullingAlarmIntent = PendingIntent.getBroadcast(
-                mContext, 0, new Intent(mContext, PullingAlarmReceiver.class), 0);
-        mPeriodicAlarmIntent = PendingIntent.getBroadcast(
-                mContext, 0, new Intent(mContext, PeriodicAlarmReceiver.class), 0);
         mAppUpdateReceiver = new AppUpdateReceiver();
         mUserUpdateReceiver = new BroadcastReceiver() {
             @Override
@@ -345,9 +340,9 @@
         }
     }
 
-    public final static class AnomalyAlarmReceiver extends BroadcastReceiver {
+    public final static class AnomalyAlarmListener implements OnAlarmListener {
         @Override
-        public void onReceive(Context context, Intent intent) {
+        public void onAlarm() {
             Slog.i(TAG, "StatsCompanionService believes an anomaly has occurred at time "
                     + System.currentTimeMillis() + "ms.");
             synchronized (sStatsdLock) {
@@ -366,9 +361,9 @@
         }
     }
 
-    public final static class PullingAlarmReceiver extends BroadcastReceiver {
+    public final static class PullingAlarmListener implements OnAlarmListener {
         @Override
-        public void onReceive(Context context, Intent intent) {
+        public void onAlarm() {
             if (DEBUG)
                 Slog.d(TAG, "Time to poll something.");
             synchronized (sStatsdLock) {
@@ -386,9 +381,9 @@
         }
     }
 
-    public final static class PeriodicAlarmReceiver extends BroadcastReceiver {
+    public final static class PeriodicAlarmListener implements OnAlarmListener {
         @Override
-        public void onReceive(Context context, Intent intent) {
+        public void onAlarm() {
             if (DEBUG)
                 Slog.d(TAG, "Time to trigger periodic alarm.");
             synchronized (sStatsdLock) {
@@ -442,9 +437,9 @@
         try {
             // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
             // only fire when it awakens.
-            // This alarm is inexact, leaving its exactness completely up to the OS optimizations.
-            // AlarmManager will automatically cancel any previous mAnomalyAlarmIntent alarm.
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mAnomalyAlarmIntent);
+            // AlarmManager will automatically cancel any previous mAnomalyAlarmListener alarm.
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".anomaly",
+                    mAnomalyAlarmListener, null);
         } finally {
             Binder.restoreCallingIdentity(callingToken);
         }
@@ -456,7 +451,7 @@
         if (DEBUG) Slog.d(TAG, "Cancelling anomaly alarm");
         final long callingToken = Binder.clearCallingIdentity();
         try {
-            mAlarmManager.cancel(mAnomalyAlarmIntent);
+            mAlarmManager.cancel(mAnomalyAlarmListener);
         } finally {
             Binder.restoreCallingIdentity(callingToken);
         }
@@ -472,7 +467,8 @@
         try {
             // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
             // only fire when it awakens.
-            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, mPeriodicAlarmIntent);
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, timestampMs, TAG + ".periodic",
+                    mPeriodicAlarmListener, null);
         } finally {
             Binder.restoreCallingIdentity(callingToken);
         }
@@ -485,7 +481,7 @@
             Slog.d(TAG, "Cancelling periodic alarm");
         final long callingToken = Binder.clearCallingIdentity();
         try {
-            mAlarmManager.cancel(mPeriodicAlarmIntent);
+            mAlarmManager.cancel(mPeriodicAlarmListener);
         } finally {
             Binder.restoreCallingIdentity(callingToken);
         }
@@ -493,31 +489,33 @@
 
     @Override // Binder call
     public void setPullingAlarm(long nextPullTimeMs) {
-      enforceCallingPermission();
-      if (DEBUG)
-        Slog.d(TAG,
-            "Setting pulling alarm in about " + (nextPullTimeMs - SystemClock.elapsedRealtime()));
-      final long callingToken = Binder.clearCallingIdentity();
-      try {
-        // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
-        // only fire when it awakens.
-        mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, mPullingAlarmIntent);
-      } finally {
-        Binder.restoreCallingIdentity(callingToken);
-      }
+        enforceCallingPermission();
+        if (DEBUG) {
+            Slog.d(TAG, "Setting pulling alarm in about "
+                    + (nextPullTimeMs - SystemClock.elapsedRealtime()));
+        }
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            // using ELAPSED_REALTIME, not ELAPSED_REALTIME_WAKEUP, so if device is asleep, will
+            // only fire when it awakens.
+            mAlarmManager.setExact(AlarmManager.ELAPSED_REALTIME, nextPullTimeMs, TAG + ".pull",
+                    mPullingAlarmListener, null);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
     }
 
     @Override // Binder call
     public void cancelPullingAlarm() {
-      enforceCallingPermission();
-      if (DEBUG)
-        Slog.d(TAG, "Cancelling pulling alarm");
-      final long callingToken = Binder.clearCallingIdentity();
-      try {
-        mAlarmManager.cancel(mPullingAlarmIntent);
-      } finally {
-        Binder.restoreCallingIdentity(callingToken);
-      }
+        enforceCallingPermission();
+        if (DEBUG)
+            Slog.d(TAG, "Cancelling pulling alarm");
+        final long callingToken = Binder.clearCallingIdentity();
+        try {
+            mAlarmManager.cancel(mPullingAlarmListener);
+        } finally {
+            Binder.restoreCallingIdentity(callingToken);
+        }
     }
 
     private void addNetworkStats(
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index a7c203d..547ab0e 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -51,6 +51,7 @@
 import android.content.pm.ServiceInfo;
 import android.content.pm.UserInfo;
 import android.content.res.Resources;
+import android.database.ContentObserver;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.BitmapRegionDecoder;
@@ -75,6 +76,7 @@
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
+import android.provider.Settings;
 import android.service.wallpaper.IWallpaperConnection;
 import android.service.wallpaper.IWallpaperEngine;
 import android.service.wallpaper.IWallpaperService;
@@ -336,6 +338,102 @@
         }
     }
 
+    /**
+     * Observes changes of theme settings. It will check whether to call
+     * notifyWallpaperColorsChanged by the current theme and updated theme.
+     * The light theme and dark theme are controlled by the hint values in Wallpaper colors,
+     * threrfore, if light theme mode is chosen, HINT_SUPPORTS_DARK_THEME in hint will be
+     * removed and then notify listeners.
+     */
+    private class ThemeSettingsObserver extends ContentObserver {
+
+        public ThemeSettingsObserver(Handler handler) {
+            super(handler);
+        }
+
+        public void startObserving(Context context) {
+            context.getContentResolver().registerContentObserver(
+                    Settings.Secure.getUriFor(Settings.Secure.THEME_MODE),
+                    false,
+                    this);
+        }
+
+        public void stopObserving(Context context) {
+            context.getContentResolver().unregisterContentObserver(this);
+        }
+
+        @Override
+        public void onChange(boolean selfChange) {
+            onThemeSettingsChanged();
+        }
+    }
+
+    /**
+     * Check whether to call notifyWallpaperColorsChanged. Assumed that the theme mode
+     * was wallpaper theme mode and dark wallpaper was set, therefoe, the theme was dark.
+     * Then theme mode changing to dark theme mode, however, theme should not update since
+     * theme was dark already.
+     */
+    private boolean needUpdateLocked(WallpaperColors colors, int themeMode) {
+        if (colors == null) {
+            return false;
+        }
+
+        if (themeMode == mThemeMode) {
+            return false;
+        }
+
+        boolean result = true;
+        boolean supportDarkTheme =
+                (colors.getColorHints() & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+        switch (themeMode) {
+            case Settings.Secure.THEME_MODE_WALLPAPER:
+                if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) {
+                    result = supportDarkTheme;
+                } else {
+                    result = !supportDarkTheme;
+                }
+                break;
+            case Settings.Secure.THEME_MODE_LIGHT:
+                if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) {
+                    result = supportDarkTheme;
+                }
+                break;
+            case Settings.Secure.THEME_MODE_DARK:
+                if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER) {
+                    result = !supportDarkTheme;
+                }
+                break;
+            default:
+                Slog.w(TAG, "unkonwn theme mode " + themeMode);
+                return false;
+        }
+        mThemeMode = themeMode;
+        return result;
+    }
+
+    void onThemeSettingsChanged() {
+        WallpaperData wallpaper;
+        synchronized (mLock) {
+            wallpaper = mWallpaperMap.get(mCurrentUserId);
+            int updatedThemeMode = Settings.Secure.getInt(
+                    mContext.getContentResolver(), Settings.Secure.THEME_MODE,
+                    Settings.Secure.THEME_MODE_WALLPAPER);
+
+            if (DEBUG) {
+                Slog.v(TAG, "onThemeSettingsChanged, mode = " + updatedThemeMode);
+            }
+
+            if (!needUpdateLocked(wallpaper.primaryColors, updatedThemeMode)) {
+                return;
+            }
+        }
+
+        if (wallpaper != null) {
+            notifyWallpaperColorsChanged(wallpaper, FLAG_SYSTEM);
+        }
+    }
+
     void notifyLockWallpaperChanged() {
         final IWallpaperManagerCallback cb = mKeyguardListener;
         if (cb != null) {
@@ -413,6 +511,7 @@
                 }
                 userAllColorListeners.finishBroadcast();
             }
+            wallpaperColors = getThemeColorsLocked(wallpaperColors);
         }
 
         final int count = colorListeners.size();
@@ -458,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();
             }
         }
@@ -481,6 +580,40 @@
     }
 
     /**
+     * We can easily change theme by modified colors hint. This function will check
+     * current theme mode and return the WallpaperColors fit current theme mode.
+     * If color need modified, it will return a copied WallpaperColors which
+     * its ColorsHint is modified to fit current theme mode.
+     *
+     * @param colors a wallpaper primary colors representation
+     */
+    private WallpaperColors getThemeColorsLocked(WallpaperColors colors) {
+        if (colors == null) {
+            Slog.w(TAG, "Cannot get theme colors because WallpaperColors is null.");
+            return null;
+        }
+
+        int colorHints = colors.getColorHints();
+        boolean supportDarkTheme = (colorHints & WallpaperColors.HINT_SUPPORTS_DARK_THEME) != 0;
+        if (mThemeMode == Settings.Secure.THEME_MODE_WALLPAPER ||
+                (mThemeMode == Settings.Secure.THEME_MODE_LIGHT && !supportDarkTheme) ||
+                (mThemeMode == Settings.Secure.THEME_MODE_DARK && supportDarkTheme)) {
+            return colors;
+        }
+
+        WallpaperColors themeColors = new WallpaperColors(colors.getPrimaryColor(),
+                colors.getSecondaryColor(), colors.getTertiaryColor());
+
+        if (mThemeMode == Settings.Secure.THEME_MODE_LIGHT) {
+            colorHints &= ~WallpaperColors.HINT_SUPPORTS_DARK_THEME;
+        } else if (mThemeMode == Settings.Secure.THEME_MODE_DARK) {
+            colorHints |= WallpaperColors.HINT_SUPPORTS_DARK_THEME;
+        }
+        themeColors.setColorHints(colorHints);
+        return themeColors;
+    }
+
+    /**
      * Once a new wallpaper has been written via setWallpaper(...), it needs to be cropped
      * for display.
      */
@@ -676,6 +809,7 @@
     final SparseArray<Boolean> mUserRestorecon = new SparseArray<Boolean>();
     int mCurrentUserId = UserHandle.USER_NULL;
     boolean mInAmbientMode;
+    int mThemeMode;
 
     static class WallpaperData {
 
@@ -734,6 +868,7 @@
         long lastDiedTime;
         boolean wallpaperUpdating;
         WallpaperObserver wallpaperObserver;
+        ThemeSettingsObserver themeSettingsObserver;
 
         /**
          * List of callbacks registered they should each be notified when the wallpaper is changed.
@@ -1279,6 +1414,10 @@
                 wallpaper.wallpaperObserver.stopWatching();
                 wallpaper.wallpaperObserver = null;
             }
+            if (wallpaper.themeSettingsObserver != null) {
+                wallpaper.themeSettingsObserver.stopObserving(mContext);
+                wallpaper.themeSettingsObserver = null;
+            }
         }
     }
 
@@ -1362,6 +1501,13 @@
                 systemWallpaper.wallpaperObserver = new WallpaperObserver(systemWallpaper);
                 systemWallpaper.wallpaperObserver.startWatching();
             }
+            if (systemWallpaper.themeSettingsObserver == null) {
+                systemWallpaper.themeSettingsObserver = new ThemeSettingsObserver(null);
+                systemWallpaper.themeSettingsObserver.startObserving(mContext);
+            }
+            mThemeMode = Settings.Secure.getInt(
+                    mContext.getContentResolver(), Settings.Secure.THEME_MODE,
+                    Settings.Secure.THEME_MODE_WALLPAPER);
             switchWallpaper(systemWallpaper, reply);
         }
 
@@ -1835,7 +1981,7 @@
         }
 
         synchronized (mLock) {
-            return wallpaperData.primaryColors;
+            return getThemeColorsLocked(wallpaperData.primaryColors);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/Dimmer.java b/services/core/java/com/android/server/wm/Dimmer.java
index b8431b1..65c8e96 100644
--- a/services/core/java/com/android/server/wm/Dimmer.java
+++ b/services/core/java/com/android/server/wm/Dimmer.java
@@ -22,7 +22,9 @@
 import static com.android.server.wm.AnimationSpecProto.ALPHA;
 
 import android.graphics.Rect;
+import android.util.Log;
 import android.util.proto.ProtoOutputStream;
+import android.view.Surface;
 import android.view.SurfaceControl;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -171,14 +173,18 @@
      */
     private DimState getDimState(WindowContainer container) {
         if (mDimState == null) {
-            final SurfaceControl ctl = makeDimLayer();
-            mDimState = new DimState(ctl);
-            /**
-             * See documentation on {@link #dimAbove} to understand lifecycle management of Dim's
-             * via state resetting for Dim's with containers.
-             */
-            if (container == null) {
-                mDimState.mDontReset = true;
+            try {
+                final SurfaceControl ctl = makeDimLayer();
+                mDimState = new DimState(ctl);
+                /**
+                 * See documentation on {@link #dimAbove} to understand lifecycle management of
+                 * Dim's via state resetting for Dim's with containers.
+                 */
+                if (container == null) {
+                    mDimState.mDontReset = true;
+                }
+            } catch (Surface.OutOfResourcesException e) {
+                Log.w(TAG, "OutOfResourcesException creating dim surface");
             }
         }
 
@@ -189,6 +195,11 @@
     private void dim(SurfaceControl.Transaction t, WindowContainer container, int relativeLayer,
             float alpha) {
         final DimState d = getDimState(container);
+
+        if (d == null) {
+            return;
+        }
+
         if (container != null) {
             // The dim method is called from WindowState.prepareSurfaces(), which is always called
             // in the correct Z from lowest Z to highest. This ensures that the dim layer is always
@@ -208,10 +219,11 @@
      * @param t A Transaction in which to finish the dim.
      */
     void stopDim(SurfaceControl.Transaction t) {
-        DimState d = getDimState(null);
-        t.hide(d.mDimLayer);
-        d.isVisible = false;
-        d.mDontReset = false;
+        if (mDimState != null) {
+            t.hide(mDimState.mDimLayer);
+            mDimState.isVisible = false;
+            mDimState.mDontReset = false;
+        }
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 50d0d0a..a709c55 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -157,10 +157,18 @@
     }
 
     WindowState computeFocusedWindow() {
+        // While the keyguard is showing, we must focus anything besides the main display.
+        // Otherwise we risk input not going to the keyguard when the user expects it to.
+        final boolean forceDefaultDisplay = mService.isKeyguardShowingAndNotOccluded();
+
         for (int i = mChildren.size() - 1; i >= 0; i--) {
             final DisplayContent dc = mChildren.get(i);
             final WindowState win = dc.findFocusedWindow();
             if (win != null) {
+                if (forceDefaultDisplay && !dc.isDefaultDisplay) {
+                    EventLog.writeEvent(0x534e4554, "71786287", win.mOwnerUid, "");
+                    continue;
+                }
                 return win;
             }
         }
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index 7211533..2bfff26 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -206,6 +206,9 @@
                 }
             }
         });
+        a.mAnim = anim;
+        mRunningAnimations.put(a.mLeash, a);
+
         anim.start();
         if (a.mAnimSpec.canSkipFirstFrame()) {
             // If we can skip the first frame, we start one frame later.
@@ -215,8 +218,6 @@
         // Immediately start the animation by manually applying an animation frame. Otherwise, the
         // start time would only be set in the next frame, leading to a delay.
         anim.doAnimationFrame(mChoreographer.getFrameTime());
-        a.mAnim = anim;
-        mRunningAnimations.put(a.mLeash, a);
     }
 
     private void applyTransformation(RunningAnimation a, Transaction t, long currentPlayTime) {
diff --git a/services/core/java/com/android/server/wm/TaskPositioner.java b/services/core/java/com/android/server/wm/TaskPositioner.java
index f73c2db..35e4092 100644
--- a/services/core/java/com/android/server/wm/TaskPositioner.java
+++ b/services/core/java/com/android/server/wm/TaskPositioner.java
@@ -29,6 +29,7 @@
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_WIDTH_IN_DP;
 
 import android.annotation.IntDef;
+import android.app.IActivityManager;
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.Looper;
@@ -93,6 +94,7 @@
     static final float MIN_ASPECT = 1.2f;
 
     private final WindowManagerService mService;
+    private final IActivityManager mActivityManager;
     private WindowPositionerEventReceiver mInputEventReceiver;
     private Display mDisplay;
     private final DisplayMetrics mDisplayMetrics = new DisplayMetrics();
@@ -165,7 +167,7 @@
                             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER,
                                     "wm.TaskPositioner.resizeTask");
                             try {
-                                mService.mActivityManager.resizeTask(
+                                mActivityManager.resizeTask(
                                         mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER);
                             } catch (RemoteException e) {
                             }
@@ -198,7 +200,7 @@
                         if (wasResizing && !mTmpRect.equals(mWindowDragBounds)) {
                             // We were using fullscreen surface during resizing. Request
                             // resizeTask() one last time to restore surface to window size.
-                            mService.mActivityManager.resizeTask(
+                            mActivityManager.resizeTask(
                                     mTask.mTaskId, mWindowDragBounds, RESIZE_MODE_USER_FORCED);
                         }
                     } catch(RemoteException e) {}
@@ -216,9 +218,15 @@
         }
     }
 
+    @VisibleForTesting
+    TaskPositioner(WindowManagerService service, IActivityManager activityManager) {
+        mService = service;
+        mActivityManager = activityManager;
+    }
+
     /** Use {@link #create(WindowManagerService)} instead **/
     TaskPositioner(WindowManagerService service) {
-        mService = service;
+        this(service, service.mActivityManager);
     }
 
     @VisibleForTesting
@@ -349,8 +357,7 @@
         startDrag(resize, preserveOrientation, startX, startY, mTmpRect);
     }
 
-    @VisibleForTesting
-    void startDrag(boolean resize, boolean preserveOrientation,
+    private void startDrag(boolean resize, boolean preserveOrientation,
                    float startX, float startY, Rect startBounds) {
         mCtrlType = CTRL_NONE;
         mStartDragX = startX;
@@ -394,7 +401,7 @@
             // guaranteed to happen before subsequent drag resizes.
             mService.mH.post(() -> {
                 try {
-                    mService.mActivityManager.resizeTask(
+                    mActivityManager.resizeTask(
                             mTask.mTaskId, startBounds, RESIZE_MODE_USER_FORCED);
                 } catch (RemoteException e) {
                 }
diff --git a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
index c366e4d..7b775f5 100644
--- a/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
+++ b/services/core/java/com/android/server/wm/WindowManagerDebugConfig.java
@@ -54,7 +54,7 @@
     static final boolean DEBUG_STARTING_WINDOW_VERBOSE = false;
     static final boolean DEBUG_STARTING_WINDOW = DEBUG_STARTING_WINDOW_VERBOSE || false;
     static final boolean DEBUG_WALLPAPER = false;
-    static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
+    static final boolean DEBUG_WALLPAPER_LIGHT = true || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
     static final boolean DEBUG_SCREEN_ON = false;
     static final boolean DEBUG_SCREENSHOT = false;
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 05626eb..ab19b82 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -2845,6 +2845,11 @@
         mH.sendEmptyMessage(H.ANIMATION_FAILSAFE);
     }
 
+    @Override
+    public void onKeyguardShowingAndNotOccludedChanged() {
+        mH.sendEmptyMessage(H.RECOMPUTE_FOCUS);
+    }
+
     /**
      * Starts deferring layout passes. Useful when doing multiple changes but to optimize
      * performance, only one layout pass should be done. This can be called multiple times, and
@@ -4615,6 +4620,7 @@
         public static final int SET_HAS_OVERLAY_UI = 58;
         public static final int SET_RUNNING_REMOTE_ANIMATION = 59;
         public static final int ANIMATION_FAILSAFE = 60;
+        public static final int RECOMPUTE_FOCUS = 61;
 
         /**
          * Used to denote that an integer field in a message will not be used.
@@ -5041,6 +5047,13 @@
                     }
                 }
                 break;
+                case RECOMPUTE_FOCUS: {
+                    synchronized (mWindowMap) {
+                        updateFocusedWindowLocked(UPDATE_FOCUS_NORMAL,
+                                true /* updateInputWindows */);
+                    }
+                }
+                break;
             }
             if (DEBUG_WINDOW_TRACE) {
                 Slog.v(TAG_WM, "handleMessage: exit");
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 7e86f3a..d580496 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -87,6 +87,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_FOCUS_LIGHT;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_INPUT_METHOD;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT;
+import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_LAYOUT_REPEATS;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_POWER;
 import static com.android.server.wm.WindowManagerDebugConfig.DEBUG_RESIZE;
@@ -2298,8 +2299,8 @@
                     if (DEBUG_FOCUS_LIGHT) Slog.i(TAG,
                             "setAnimationLocked: setting mFocusMayChange true");
                     mService.mFocusMayChange = true;
-                    setDisplayLayoutNeeded();
                 }
+                setDisplayLayoutNeeded();
                 // Window is no longer visible -- make sure if we were waiting
                 // for it to be displayed before enabling the display, that
                 // we allow the display to be enabled now.
@@ -4210,10 +4211,15 @@
         }
         if (!mWinAnimator.mLastHidden || wasDeferred) {
             mWinAnimator.hide(reason);
+            getDisplayContent().mWallpaperController.mDeferredHideWallpaper = null;
             dispatchWallpaperVisibility(false);
             final DisplayContent displayContent = getDisplayContent();
             if (displayContent != null) {
                 displayContent.pendingLayoutChanges |= FINISH_LAYOUT_REDO_WALLPAPER;
+                if (DEBUG_LAYOUT_REPEATS) {
+                    mService.mWindowPlacerLocked.debugLayoutRepeats("hideWallpaperWindow " + this,
+                            displayContent.pendingLayoutChanges);
+                }
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 3eef125..561c9de 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -1115,7 +1115,7 @@
 
         setSurfaceBoundariesLocked(recoveringMemory);
 
-        if (mIsWallpaper && !mWin.mWallpaperVisible) {
+        if (mIsWallpaper && !w.mWallpaperVisible) {
             // Wallpaper is no longer visible and there is no wp target => hide it.
             hide("prepareSurfaceLocked");
         } else if (w.isParentWindowHidden() || !w.isOnScreen()) {
@@ -1179,6 +1179,11 @@
                         // LogicalDisplay.
                         mAnimator.setPendingLayoutChanges(w.getDisplayId(),
                                 FINISH_LAYOUT_REDO_ANIM);
+                        if (DEBUG_LAYOUT_REPEATS) {
+                            mService.mWindowPlacerLocked.debugLayoutRepeats(
+                                    "showSurfaceRobustlyLocked " + w,
+                                    mAnimator.getPendingLayoutChanges(w.getDisplayId()));
+                        }
                     } else {
                         w.setOrientationChanging(false);
                     }
diff --git a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
index 70287db..d247960 100644
--- a/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
+++ b/services/core/java/com/android/server/wm/WindowSurfacePlacer.java
@@ -644,6 +644,11 @@
                 ? null : wallpaperTarget;
         final ArraySet<AppWindowToken> openingApps = mService.mOpeningApps;
         final ArraySet<AppWindowToken> closingApps = mService.mClosingApps;
+        final AppWindowToken topOpeningApp = getTopApp(mService.mOpeningApps,
+                false /* ignoreHidden */);
+        final AppWindowToken topClosingApp = getTopApp(mService.mClosingApps,
+                true /* ignoreHidden */);
+
         boolean openingCanBeWallpaperTarget = canBeWallpaperTarget(openingApps);
         if (DEBUG_APP_TRANSITIONS) Slog.v(TAG,
                 "New wallpaper target=" + wallpaperTarget
@@ -677,13 +682,15 @@
                         "New transit: " + AppTransition.appTransitionToString(transit));
             } else if (oldWallpaper != null && !mService.mOpeningApps.isEmpty()
                     && !openingApps.contains(oldWallpaper.mAppToken)
-                    && closingApps.contains(oldWallpaper.mAppToken)) {
+                    && closingApps.contains(oldWallpaper.mAppToken)
+                    && topClosingApp == oldWallpaper.mAppToken) {
                 // We are transitioning from an activity with a wallpaper to one without.
                 transit = TRANSIT_WALLPAPER_CLOSE;
                 if (DEBUG_APP_TRANSITIONS) Slog.v(TAG, "New transit away from wallpaper: "
                         + AppTransition.appTransitionToString(transit));
             } else if (wallpaperTarget != null && wallpaperTarget.isVisibleLw()
                     && openingApps.contains(wallpaperTarget.mAppToken)
+                    && topOpeningApp == wallpaperTarget.mAppToken
                     && transit != TRANSIT_TRANSLUCENT_ACTIVITY_CLOSE) {
                 // We are transitioning from an activity without
                 // a wallpaper to now showing the wallpaper
@@ -748,6 +755,31 @@
         return false;
     }
 
+    /**
+     * Finds the top app in a list of apps, using its {@link AppWindowToken#getPrefixOrderIndex} to
+     * compare z-order.
+     *
+     * @param apps The list of apps to search.
+     * @param ignoreHidden If set to true, ignores apps that are {@link AppWindowToken#isHidden}.
+     * @return The top {@link AppWindowToken}.
+     */
+    private AppWindowToken getTopApp(ArraySet<AppWindowToken> apps, boolean ignoreHidden) {
+        int topPrefixOrderIndex = Integer.MIN_VALUE;
+        AppWindowToken topApp = null;
+        for (int i = apps.size() - 1; i >= 0; i--) {
+            final AppWindowToken app = apps.valueAt(i);
+            if (ignoreHidden && app.isHidden()) {
+                continue;
+            }
+            final int prefixOrderIndex = app.getPrefixOrderIndex();
+            if (prefixOrderIndex > topPrefixOrderIndex) {
+                topPrefixOrderIndex = prefixOrderIndex;
+                topApp = app;
+            }
+        }
+        return topApp;
+    }
+
     private void processApplicationsAnimatingInPlace(int transit) {
         if (transit == TRANSIT_TASK_IN_PLACE) {
             // Find the focused window
diff --git a/services/net/java/android/net/dns/ResolvUtil.java b/services/net/java/android/net/dns/ResolvUtil.java
index a2a6615..d9d4b96 100644
--- a/services/net/java/android/net/dns/ResolvUtil.java
+++ b/services/net/java/android/net/dns/ResolvUtil.java
@@ -16,6 +16,8 @@
 
 package android.net.dns;
 
+import static android.system.OsConstants.AI_ADDRCONFIG;
+
 import android.net.Network;
 import android.net.NetworkUtils;
 import android.system.GaiException;
@@ -41,12 +43,17 @@
 
     public static InetAddress[] blockingResolveAllLocally(Network network, String name)
             throws UnknownHostException {
+        // Use AI_ADDRCONFIG by default
+        return blockingResolveAllLocally(network, name, AI_ADDRCONFIG);
+    }
+
+    public static InetAddress[] blockingResolveAllLocally(
+            Network network, String name, int aiFlags) throws UnknownHostException  {
         final StructAddrinfo hints = new StructAddrinfo();
-        // Unnecessary, but expressly no AI_ADDRCONFIG.
-        hints.ai_flags = 0;
-        // Fetch all IP addresses at once to minimize re-resolution.
+        hints.ai_flags = aiFlags;
+        // Other hints identical to the default Inet6AddressImpl implementation
         hints.ai_family = OsConstants.AF_UNSPEC;
-        hints.ai_socktype = OsConstants.SOCK_DGRAM;
+        hints.ai_socktype = OsConstants.SOCK_STREAM;
 
         final Network networkForResolv = getNetworkWithUseLocalNameserversFlag(network);
 
diff --git a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
index 340100f..d16bc26 100644
--- a/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
+++ b/services/robotests/src/com/android/server/backup/BackupManagerServiceTest.java
@@ -22,9 +22,7 @@
 import static com.android.server.backup.testing.TransportData.localTransport;
 import static com.android.server.backup.testing.TransportTestUtils.setUpCurrentTransport;
 import static com.android.server.backup.testing.TransportTestUtils.setUpTransports;
-
 import static com.google.common.truth.Truth.assertThat;
-
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
@@ -43,9 +41,10 @@
 import android.content.ContextWrapper;
 import android.content.Intent;
 import android.os.HandlerThread;
+import android.os.PowerManager;
+import android.os.PowerSaveState;
 import android.platform.test.annotations.Presubmit;
 import android.provider.Settings;
-
 import com.android.server.backup.internal.BackupRequest;
 import com.android.server.backup.testing.TransportData;
 import com.android.server.backup.testing.TransportTestUtils.TransportMock;
@@ -54,8 +53,11 @@
 import com.android.server.testing.SystemLoaderPackages;
 import com.android.server.testing.shadows.ShadowAppBackupUtils;
 import com.android.server.testing.shadows.ShadowBackupPolicyEnforcer;
+import com.android.server.testing.shadows.ShadowBinder;
+import com.android.server.testing.shadows.ShadowKeyValueBackupJob;
 import com.android.server.testing.shadows.ShadowPerformBackupTask;
-
+import java.io.File;
+import java.util.List;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
@@ -64,6 +66,7 @@
 import org.mockito.MockitoAnnotations;
 import org.robolectric.RuntimeEnvironment;
 import org.robolectric.annotation.Config;
+import org.robolectric.annotation.Implements;
 import org.robolectric.shadows.ShadowContextWrapper;
 import org.robolectric.shadows.ShadowLog;
 import org.robolectric.shadows.ShadowLooper;
@@ -71,15 +74,11 @@
 import org.robolectric.shadows.ShadowSettings;
 import org.robolectric.shadows.ShadowSystemClock;
 
-import java.io.File;
-import java.util.List;
-
 @RunWith(FrameworkRobolectricTestRunner.class)
 @Config(
-    manifest = Config.NONE,
-    sdk = 26,
-    shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class}
-)
+        manifest = Config.NONE,
+        sdk = 26,
+        shadows = {ShadowAppBackupUtils.class, ShadowBackupPolicyEnforcer.class})
 @SystemLoaderPackages({"com.android.server.backup"})
 @Presubmit
 public class BackupManagerServiceTest {
@@ -406,6 +405,51 @@
                 mContext.getContentResolver(), Settings.Secure.BACKUP_TRANSPORT);
     }
 
+    /* Tests for transport attributes */
+
+    @Test
+    public void testGetCurrentTransportComponent() throws Exception {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        when(mTransportManager.getCurrentTransportComponent())
+                .thenReturn(mTransport.getTransportComponent());
+        BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+        ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
+
+        assertThat(transportComponent).isEqualTo(mTransport.getTransportComponent());
+    }
+
+    @Test
+    public void testGetCurrentTransportComponent_whenNoTransportSelected() throws Exception {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        when(mTransportManager.getCurrentTransportComponent()).thenReturn(null);
+        BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+        ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
+
+        assertThat(transportComponent).isNull();
+    }
+
+    @Test
+    public void testGetCurrentTransportComponent_whenTransportNotRegistered() throws Exception {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        when(mTransportManager.getCurrentTransportComponent())
+                .thenThrow(TransportNotRegisteredException.class);
+        BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+        ComponentName transportComponent = backupManagerService.getCurrentTransportComponent();
+
+        assertThat(transportComponent).isNull();
+    }
+
+    @Test
+    public void testGetCurrentTransportComponent_withoutPermission() throws Exception {
+        mShadowContext.denyPermissions(android.Manifest.permission.BACKUP);
+        BackupManagerService backupManagerService = createInitializedBackupManagerService();
+
+        expectThrows(SecurityException.class, backupManagerService::getCurrentTransportComponent);
+    }
+
     /* Tests for updating transport attributes */
 
     private static final int PACKAGE_UID = 10;
@@ -752,6 +796,34 @@
         tearDownForRequestBackup();
     }
 
+    @Test
+    @Config(shadows = {ShadowBinder.class, ShadowKeyValueBackupJob.class})
+    public void testBackupNow_clearsCallingIdentityForJobScheduler() {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        BackupManagerService backupManagerService = createInitializedBackupManagerService();
+        setUpPowerManager(backupManagerService);
+        ShadowBinder.setCallingUid(1);
+
+        backupManagerService.backupNow();
+
+        assertThat(ShadowKeyValueBackupJob.getCallingUid()).isEqualTo(ShadowBinder.LOCAL_UID);
+        assertThat(ShadowBinder.getCallingUid()).isEqualTo(1);
+    }
+
+    @Test
+    @Config(shadows = {ShadowBinder.class, ShadowKeyValueBackupJobException.class})
+    public void testBackupNow_whenExceptionThrown_restoresCallingIdentity() {
+        mShadowContext.grantPermissions(android.Manifest.permission.BACKUP);
+        BackupManagerService backupManagerService = createInitializedBackupManagerService();
+        setUpPowerManager(backupManagerService);
+        ShadowBinder.setCallingUid(1);
+
+        expectThrows(IllegalArgumentException.class, backupManagerService::backupNow);
+        assertThat(ShadowKeyValueBackupJobException.getCallingUid())
+                .isEqualTo(ShadowBinder.LOCAL_UID);
+        assertThat(ShadowBinder.getCallingUid()).isEqualTo(1);
+    }
+
     private BackupManagerService createBackupManagerServiceForRequestBackup() {
         BackupManagerService backupManagerService = createInitializedBackupManagerService();
         backupManagerService.setEnabled(true);
@@ -809,4 +881,23 @@
         ShadowSystemClock.setCurrentTimeMillis(mShadowBackupLooper.getScheduler().getCurrentTime());
         return backupManagerService;
     }
+
+    private void setUpPowerManager(BackupManagerService backupManagerService) {
+        PowerManager powerManagerMock = mock(PowerManager.class);
+        when(powerManagerMock.getPowerSaveState(anyInt()))
+                .thenReturn(new PowerSaveState.Builder().setBatterySaverEnabled(true).build());
+        backupManagerService.setPowerManager(powerManagerMock);
+    }
+
+    /**
+     * We can't mock the void method {@link #schedule(Context, long, BackupManagerConstants)} so we
+     * extend {@link ShadowKeyValueBackupJob} and throw an exception at the end of the method.
+     */
+    @Implements(KeyValueBackupJob.class)
+    public static class ShadowKeyValueBackupJobException extends ShadowKeyValueBackupJob {
+        public static void schedule(Context ctx, long delay, BackupManagerConstants constants) {
+            ShadowKeyValueBackupJob.schedule(ctx, delay, constants);
+            throw new IllegalArgumentException();
+        }
+    }
 }
diff --git a/services/robotests/src/com/android/server/backup/TransportManagerTest.java b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
index c2e7595..051a4a0 100644
--- a/services/robotests/src/com/android/server/backup/TransportManagerTest.java
+++ b/services/robotests/src/com/android/server/backup/TransportManagerTest.java
@@ -77,10 +77,9 @@
 
 @RunWith(FrameworkRobolectricTestRunner.class)
 @Config(
-    manifest = Config.NONE,
-    sdk = 26,
-    shadows = {FrameworkShadowContextImpl.class}
-)
+        manifest = Config.NONE,
+        sdk = 26,
+        shadows = {FrameworkShadowContextImpl.class})
 @SystemLoaderPackages({"com.android.server.backup"})
 @Presubmit
 public class TransportManagerTest {
@@ -394,6 +393,36 @@
     }
 
     @Test
+    public void testGetCurrentTransportComponent() throws Exception {
+        TransportManager transportManager =
+                createTransportManagerWithRegisteredTransports(mTransportA1);
+
+        ComponentName transportComponent = transportManager.getCurrentTransportComponent();
+
+        assertThat(transportComponent).isEqualTo(mTransportA1.getTransportComponent());
+    }
+
+    @Test
+    public void testGetCurrentTransportComponent_whenNoTransportSelected() throws Exception {
+        TransportManager transportManager =
+                createTransportManagerWithRegisteredTransports(null, mTransportA1);
+
+        ComponentName transportComponent = transportManager.getCurrentTransportComponent();
+
+        assertThat(transportComponent).isNull();
+    }
+
+    @Test
+    public void testGetCurrentTransportComponent_whenTransportNotRegistered() throws Exception {
+        TransportManager transportManager =
+                createTransportManagerWithRegisteredTransports(mTransportA1.unregistered());
+
+        expectThrows(
+                TransportNotRegisteredException.class,
+                transportManager::getCurrentTransportComponent);
+    }
+
+    @Test
     public void testGetTransportClient_forRegisteredTransport() throws Exception {
         TransportManager transportManager =
                 createTransportManagerWithRegisteredTransports(mTransportA1, mTransportA2);
diff --git a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
index 1fbadd4..5844131 100644
--- a/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
+++ b/services/robotests/src/com/android/server/backup/testing/TransportTestUtils.java
@@ -55,6 +55,9 @@
             ShadowPackageManager shadowPackageManager, TransportData... transports)
             throws Exception {
         for (TransportData transport : transports) {
+            if (transport.transportStatus == TransportStatus.UNREGISTERED) {
+                continue;
+            }
             ComponentName transportComponent = transport.getTransportComponent();
             String packageName = transportComponent.getPackageName();
             ResolveInfo resolveInfo = resolveInfo(transportComponent);
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowBinder.java b/services/robotests/src/com/android/server/testing/shadows/ShadowBinder.java
new file mode 100644
index 0000000..043d44b
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowBinder.java
@@ -0,0 +1,44 @@
+/*
+ * 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
+ */
+
+package com.android.server.testing.shadows;
+
+import android.os.Binder;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+/**
+ * Extends {@link org.robolectric.shadows.ShadowBinder} with {@link Binder#clearCallingIdentity()}
+ * and {@link Binder#restoreCallingIdentity(long)}. Uses a hardcoded default {@link #LOCAL_UID} to
+ * mimic the local process uid.
+ */
+@Implements(Binder.class)
+public class ShadowBinder extends org.robolectric.shadows.ShadowBinder {
+    public static final Integer LOCAL_UID = 1000;
+    private static Integer originalCallingUid;
+
+    @Implementation
+    public static long clearCallingIdentity() {
+        originalCallingUid = getCallingUid();
+        setCallingUid(LOCAL_UID);
+        return 1L;
+    }
+
+    @Implementation
+    public static void restoreCallingIdentity(long token) {
+        setCallingUid(originalCallingUid);
+    }
+}
diff --git a/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
new file mode 100644
index 0000000..3941f17
--- /dev/null
+++ b/services/robotests/src/com/android/server/testing/shadows/ShadowKeyValueBackupJob.java
@@ -0,0 +1,38 @@
+/*
+ * 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
+ */
+
+package com.android.server.testing.shadows;
+
+import android.content.Context;
+import android.os.Binder;
+import com.android.server.backup.BackupManagerConstants;
+import com.android.server.backup.KeyValueBackupJob;
+import org.robolectric.annotation.Implementation;
+import org.robolectric.annotation.Implements;
+
+@Implements(KeyValueBackupJob.class)
+public class ShadowKeyValueBackupJob {
+    private static int callingUid;
+
+    public static int getCallingUid() {
+        return callingUid;
+    }
+
+    @Implementation
+    public static void schedule(Context ctx, long delay, BackupManagerConstants constants) {
+        callingUid = Binder.getCallingUid();
+    }
+}
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/AppStateTrackerTest.java b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
index 5daacd7..933b3d6 100644
--- a/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
+++ b/services/tests/servicestests/src/com/android/server/AppStateTrackerTest.java
@@ -445,7 +445,7 @@
         areRestricted(instance, UID_10_3, PACKAGE_3, JOBS_AND_ALARMS);
         areRestricted(instance, Process.SYSTEM_UID, PACKAGE_SYSTEM, NONE);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {UID_2});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1}, new int[] {}, new int[] {UID_2});
 
         areRestricted(instance, UID_1, PACKAGE_1, NONE);
         areRestricted(instance, UID_10_1, PACKAGE_1, NONE);
@@ -482,6 +482,15 @@
     }
 
     @Test
+    public void testPowerSaveUserWhitelist() throws Exception {
+        final AppStateTrackerTestable instance = newInstance();
+        instance.setPowerSaveWhitelistAppIds(new int[] {}, new int[] {UID_1, UID_2}, new int[] {});
+        assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_1));
+        assertTrue(instance.isUidPowerSaveUserWhitelisted(UID_2));
+        assertFalse(instance.isUidPowerSaveUserWhitelisted(UID_3));
+    }
+
+    @Test
     public void testUidStateForeground() throws Exception {
         final AppStateTrackerTestable instance = newInstance();
         callStart(instance);
@@ -861,7 +870,7 @@
         // -------------------------------------------------------------------------
         // Tests with system/user/temp whitelist.
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -873,7 +882,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -886,7 +895,8 @@
         reset(l);
 
         // Update temp whitelist.
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_1, UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+                new int[] {UID_1, UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -898,7 +908,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -924,7 +934,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_1, UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         // Called once for updating all whitelist and once for updating temp whitelist
@@ -937,7 +947,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -950,7 +960,8 @@
         reset(l);
 
         // Update temp whitelist.
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_1, UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {},
+                new int[] {UID_1, UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
@@ -962,7 +973,7 @@
         verify(l, times(0)).unblockAlarmsForUidPackage(anyInt(), anyString());
         reset(l);
 
-        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {UID_3});
+        instance.setPowerSaveWhitelistAppIds(new int[] {UID_2}, new int[] {}, new int[] {UID_3});
 
         waitUntilMainHandlerDrain();
         verify(l, times(1)).updateAllJobs();
diff --git a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
index b4dc941..17babe9 100644
--- a/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/NetworkPolicyManagerServiceTest.java
@@ -1628,6 +1628,20 @@
         }
     }
 
+    /**
+     * Test that policy set of {null, NetworkPolicy, null} does not crash and restores the valid
+     * NetworkPolicy.
+     */
+    @Test
+    public void testSetNetworkPolicies_withNullPolicies_doesNotThrow() {
+        NetworkPolicy[] policies = new NetworkPolicy[3];
+        policies[1] = buildDefaultFakeMobilePolicy();
+        setNetworkPolicies(policies);
+
+        assertNetworkPolicyEquals(DEFAULT_CYCLE_DAY, mDefaultWarningBytes, mDefaultLimitBytes,
+                true);
+    }
+
     private SubscriptionPlan buildMonthlyDataPlan(ZonedDateTime start, long limitBytes) {
         return SubscriptionPlan.Builder
                 .createRecurringMonthly(start)
diff --git a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
index ea0fe45..7f397d6 100644
--- a/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/appops/AppOpsActiveWatcherTest.java
@@ -18,6 +18,8 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.reset;
@@ -36,6 +38,8 @@
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.util.List;
+
 /**
  * Tests app ops version upgrades
  */
@@ -107,6 +111,46 @@
         verifyNoMoreInteractions(listener);
     }
 
+    @Test
+    public void testIsRunning() throws Exception {
+        final AppOpsManager appOpsManager = getContext().getSystemService(AppOpsManager.class);
+        // Start the op
+        appOpsManager.startOp(AppOpsManager.OP_CAMERA);
+
+        assertTrue("Camera should be running", isCameraOn(appOpsManager));
+
+        // Finish the op
+        appOpsManager.finishOp(AppOpsManager.OP_CAMERA);
+
+        assertFalse("Camera should not be running", isCameraOn(appOpsManager));
+    }
+
+    private boolean isCameraOn(AppOpsManager appOpsManager) {
+        List<AppOpsManager.PackageOps> packages
+                = appOpsManager.getPackagesForOps(new int[] {AppOpsManager.OP_CAMERA});
+        // AppOpsManager can return null when there is no requested data.
+        if (packages != null) {
+            final int numPackages = packages.size();
+            for (int packageInd = 0; packageInd < numPackages; packageInd++) {
+                AppOpsManager.PackageOps packageOp = packages.get(packageInd);
+                List<AppOpsManager.OpEntry> opEntries = packageOp.getOps();
+                if (opEntries != null) {
+                    final int numOps = opEntries.size();
+                    for (int opInd = 0; opInd < numOps; opInd++) {
+                        AppOpsManager.OpEntry opEntry = opEntries.get(opInd);
+                        if (opEntry.getOp() == AppOpsManager.OP_CAMERA) {
+                            if (opEntry.isRunning()) {
+                                return true;
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+        return false;
+    }
+
     private static Context getContext() {
         return InstrumentationRegistry.getContext();
     }
diff --git a/services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
similarity index 99%
rename from services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java
rename to services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
index c004074..6bd8011 100644
--- a/services/tests/servicestests/src/com/android/server/ColorDisplayServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/display/ColorDisplayServiceTest.java
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.server;
+package com.android.server.display;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -32,8 +32,8 @@
 
 import com.android.internal.app.ColorDisplayController;
 import com.android.internal.util.test.FakeSettingsProvider;
-import com.android.server.display.DisplayTransformManager;
-import com.android.server.display.ColorDisplayService;
+import com.android.server.LocalServices;
+import com.android.server.SystemService;
 import com.android.server.twilight.TwilightListener;
 import com.android.server.twilight.TwilightManager;
 import com.android.server.twilight.TwilightState;
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
new file mode 100644
index 0000000..1089f69
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecControllerTest.java
@@ -0,0 +1,272 @@
+/*
+ * 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.
+ */
+package com.android.server.hdmi;
+
+import android.content.Context;
+import android.hardware.hdmi.HdmiPortInfo;
+import android.os.Looper;
+import android.os.MessageQueue;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.util.Log;
+import com.android.server.hdmi.HdmiCecController.AllocateAddressCallback;
+import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_AUDIO_SYSTEM;
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_PLAYBACK;
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+import static com.android.server.hdmi.Constants.ADDR_AUDIO_SYSTEM;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_1;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_2;
+import static com.android.server.hdmi.Constants.ADDR_PLAYBACK_3;
+import static com.android.server.hdmi.Constants.ADDR_SPECIFIC_USE;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+import static junit.framework.Assert.assertEquals;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+/**
+ * Tests for {@link com.android.server.hdmi.HdmiCecController} class.
+ */
+@SmallTest
+@RunWith(JUnit4.class)
+public class HdmiCecControllerTest {
+
+    private static final class NativeWrapperImpl implements NativeWrapper {
+
+        @Override
+        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
+            return 1L;
+        }
+
+        @Override
+        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
+            byte[] body) {
+            return mOccupied[srcAddress] ? 0 : 1;
+        }
+
+        @Override
+        public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
+            return 0;
+        }
+
+        @Override
+        public void nativeClearLogicalAddress(long controllerPtr) {
+
+        }
+
+        @Override
+        public int nativeGetPhysicalAddress(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public int nativeGetVersion(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public int nativeGetVendorId(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
+            return new HdmiPortInfo[0];
+        }
+
+        @Override
+        public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {
+
+        }
+
+        @Override
+        public void nativeSetLanguage(long controllerPtr, String language) {
+
+        }
+
+        @Override
+        public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
+
+        }
+
+        @Override
+        public boolean nativeIsConnected(long controllerPtr, int port) {
+            return false;
+        }
+    }
+
+    private class MyHdmiControlService extends HdmiControlService {
+
+        MyHdmiControlService(Context context) {
+            super(context);
+        }
+
+        @Override
+        Looper getIoLooper() {
+            return mMyLooper;
+        }
+
+        @Override
+        Looper getServiceLooper() {
+            return mMyLooper;
+        }
+    }
+
+    private static final String TAG = HdmiCecControllerTest.class.getSimpleName();
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private static boolean[] mOccupied = new boolean[15];
+    private int mLogicalAddress = 16;
+    private AllocateAddressCallback mCallback = new AllocateAddressCallback() {
+        @Override
+        public void onAllocated(int deviceType, int logicalAddress) {
+            mLogicalAddress = logicalAddress;
+        }
+    };
+    private Looper mMyLooper;
+    private TestLooper mTestLooper = new TestLooper();
+
+    @Before
+    public void SetUp() {
+        mMyLooper = mTestLooper.getLooper();
+        mMyLooper = mTestLooper.getLooper();
+        mHdmiControlService = new MyHdmiControlService(null);
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+            mHdmiControlService, new NativeWrapperImpl());
+    }
+
+    /**
+     * Tests for {@link HdmiCecController#allocateLogicalAddress}
+     */
+    @Test
+    public void testAllocatLogicalAddress_TvDevicePreferredNotOcupied() {
+        mOccupied[ADDR_TV] = false;
+        mOccupied[ADDR_SPECIFIC_USE] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_TV, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_TV, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_TvDeviceNonPreferredNotOcupied() {
+        mOccupied[ADDR_TV] = false;
+        mOccupied[ADDR_SPECIFIC_USE] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_TV, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_TvDeviceNonPreferredFirstOcupied() {
+        mOccupied[ADDR_TV] = true;
+        mOccupied[ADDR_SPECIFIC_USE] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_SPECIFIC_USE, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_TvDeviceNonPreferredAllOcupied() {
+        mOccupied[ADDR_TV] = true;
+        mOccupied[ADDR_SPECIFIC_USE] = true;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_TV, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_AudioSystemNonPreferredNotOcupied() {
+        mOccupied[ADDR_AUDIO_SYSTEM] = false;
+        mHdmiCecController.allocateLogicalAddress(
+            DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_AUDIO_SYSTEM, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_AudioSystemNonPreferredAllOcupied() {
+        mOccupied[ADDR_AUDIO_SYSTEM] = true;
+        mHdmiCecController.allocateLogicalAddress(
+            DEVICE_AUDIO_SYSTEM, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_PlaybackPreferredNotOccupied() {
+        mOccupied[ADDR_PLAYBACK_1] = false;
+        mOccupied[ADDR_PLAYBACK_2] = false;
+        mOccupied[ADDR_PLAYBACK_3] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_PLAYBACK_1, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_PlaybackPreferredOcuppied() {
+        mOccupied[ADDR_PLAYBACK_1] = true;
+        mOccupied[ADDR_PLAYBACK_2] = false;
+        mOccupied[ADDR_PLAYBACK_3] = false;
+        mHdmiCecController.allocateLogicalAddress(
+            DEVICE_PLAYBACK, ADDR_PLAYBACK_1, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_PlaybackNoPreferredNotOcuppied() {
+        mOccupied[ADDR_PLAYBACK_1] = false;
+        mOccupied[ADDR_PLAYBACK_2] = false;
+        mOccupied[ADDR_PLAYBACK_3] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_PLAYBACK_1, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_PlaybackNoPreferredFirstOcuppied() {
+        mOccupied[ADDR_PLAYBACK_1] = true;
+        mOccupied[ADDR_PLAYBACK_2] = false;
+        mOccupied[ADDR_PLAYBACK_3] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_PLAYBACK_2, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_PlaybackNonPreferredFirstTwoOcuppied() {
+        mOccupied[ADDR_PLAYBACK_1] = true;
+        mOccupied[ADDR_PLAYBACK_2] = true;
+        mOccupied[ADDR_PLAYBACK_3] = false;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_PLAYBACK_3, mLogicalAddress);
+    }
+
+    @Test
+    public void testAllocatLogicalAddress_PlaybackNonPreferredAllOcupied() {
+        mOccupied[ADDR_PLAYBACK_1] = true;
+        mOccupied[ADDR_PLAYBACK_2] = true;
+        mOccupied[ADDR_PLAYBACK_3] = true;
+        mHdmiCecController.allocateLogicalAddress(DEVICE_PLAYBACK, ADDR_UNREGISTERED, mCallback);
+        mTestLooper.dispatchAll();
+        assertEquals(ADDR_UNREGISTERED, mLogicalAddress);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
new file mode 100644
index 0000000..78cb56b
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/hdmi/HdmiCecLocalDeviceTest.java
@@ -0,0 +1,221 @@
+/*
+ * 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.
+ */
+package com.android.server.hdmi;
+
+import static android.hardware.hdmi.HdmiDeviceInfo.DEVICE_TV;
+import static com.android.server.hdmi.Constants.ADDR_BROADCAST;
+import static com.android.server.hdmi.Constants.ADDR_TV;
+import static com.android.server.hdmi.Constants.ADDR_UNREGISTERED;
+import static com.android.server.hdmi.Constants.MESSAGE_DEVICE_VENDOR_ID;
+import static com.android.server.hdmi.Constants.MESSAGE_REPORT_PHYSICAL_ADDRESS;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import android.hardware.hdmi.HdmiPortInfo;
+import android.os.test.TestLooper;
+import android.support.test.filters.SmallTest;
+import android.os.MessageQueue;
+import com.android.server.hdmi.HdmiCecController.NativeWrapper;
+import junit.framework.Assert;
+import java.util.Arrays;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.junit.runners.JUnit4;
+
+@SmallTest
+@RunWith(JUnit4.class)
+/**
+ * Tests for {@link HdmiCecLocalDevice} class.
+ */
+public class HdmiCecLocalDeviceTest {
+
+    private static final class NativeWrapperImpl implements NativeWrapper {
+
+        @Override
+        public long nativeInit(HdmiCecController handler, MessageQueue messageQueue) {
+            return 1L;
+        }
+
+        @Override
+        public int nativeSendCecCommand(long controllerPtr, int srcAddress, int dstAddress,
+            byte[] body) {
+            return SendCecCommandFactory(srcAddress, dstAddress, body);
+        }
+
+        @Override
+        public int nativeAddLogicalAddress(long controllerPtr, int logicalAddress) {
+            return 0;
+        }
+
+        @Override
+        public void nativeClearLogicalAddress(long controllerPtr) {
+
+        }
+
+        @Override
+        public int nativeGetPhysicalAddress(long controllerPtr) {
+            return mPhysicalAddr;
+        }
+
+        @Override
+        public int nativeGetVersion(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public int nativeGetVendorId(long controllerPtr) {
+            return 0;
+        }
+
+        @Override
+        public HdmiPortInfo[] nativeGetPortInfos(long controllerPtr) {
+            return new HdmiPortInfo[0];
+        }
+
+        @Override
+        public void nativeSetOption(long controllerPtr, int flag, boolean enabled) {
+
+        }
+
+        @Override
+        public void nativeSetLanguage(long controllerPtr, String language) {
+
+        }
+
+        @Override
+        public void nativeEnableAudioReturnChannel(long controllerPtr, int port, boolean flag) {
+
+        }
+
+        @Override
+        public boolean nativeIsConnected(long controllerPtr, int port) {
+            return false;
+        }
+    }
+
+    private static int SendCecCommandFactory(int srcAddress, int dstAddress, byte[] body) {
+        switch(body[0] & 0xFF) {
+            /** {@link Constants#MESSAGE_GIVE_PHYSICAL_ADDRESS} */
+            case MESSAGE_REPORT_PHYSICAL_ADDRESS:
+            case MESSAGE_DEVICE_VENDOR_ID:
+                return srcAddress == mSrcAddr &&
+                    dstAddress == mDesAddr &&
+                    Arrays.equals(Arrays.copyOfRange(body, 1, body.length), param)? 0 : 1;
+            default:
+                return 1;
+        }
+    }
+
+    private class MyHdmiCecLocalDevice extends HdmiCecLocalDevice {
+
+
+        protected MyHdmiCecLocalDevice(HdmiControlService service, int deviceType) {
+            super(service, deviceType);
+        }
+
+        @Override
+        protected void onAddressAllocated(int logicalAddress, int reason) {
+
+        }
+
+        @Override
+        protected int getPreferredAddress() {
+            return 0;
+        }
+
+        @Override
+        protected void setPreferredAddress(int addr) {
+
+        }
+    }
+
+    private MyHdmiCecLocalDevice mHdmiLocalDevice;
+    private HdmiControlService mHdmiControlService;
+    private HdmiCecController mHdmiCecController;
+    private TestLooper mTestLooper = new TestLooper();
+    private static int mDesAddr = -1;
+    private static int mSrcAddr = -1;
+    private static int mPhysicalAddr = 2;
+    private int callbackResult;
+    private HdmiCecMessageValidator mMessageValidator;
+    private static byte[] param;
+
+    @Before
+    public void SetUp() {
+        mHdmiControlService = new HdmiControlService(null);
+        mHdmiControlService.setIoLooper(mTestLooper.getLooper());
+        mHdmiCecController = HdmiCecController.createWithNativeWrapper(
+            mHdmiControlService, new NativeWrapperImpl());
+        mHdmiControlService.setCecController(mHdmiCecController);
+        mHdmiLocalDevice = new MyHdmiCecLocalDevice(
+            mHdmiControlService, DEVICE_TV);
+        mMessageValidator = new HdmiCecMessageValidator(mHdmiControlService){
+            @Override
+            int isValid(HdmiCecMessage message) {
+                return HdmiCecMessageValidator.OK;
+            }
+        };
+        mHdmiControlService.setMessageValidator(mMessageValidator);
+    }
+
+    @Test
+    public void dispatchMessage_desNotValid() {
+        HdmiCecMessage msg = new HdmiCecMessage(
+            ADDR_TV, ADDR_TV, Constants.MESSAGE_CEC_VERSION, HdmiCecMessage.EMPTY_PARAM);
+        boolean handleResult = mHdmiLocalDevice.dispatchMessage(msg);
+        assertFalse(handleResult);
+    }
+
+    @Test
+    public void handleGivePhysicalAddress_success() {
+        mSrcAddr = ADDR_UNREGISTERED;
+        mDesAddr = ADDR_BROADCAST;
+        param = new byte[] {
+            (byte) ((mPhysicalAddr >> 8) & 0xFF),
+            (byte) (mPhysicalAddr & 0xFF),
+            (byte) (DEVICE_TV & 0xFF)
+        };
+        callbackResult = -1;
+        boolean handleResult = mHdmiLocalDevice.handleGivePhysicalAddress(
+            (int finalResult) -> callbackResult = finalResult);
+        mTestLooper.dispatchAll();
+        /**
+         * Test if CecMessage is sent successfully
+         * SendMessageResult#SUCCESS is defined in HAL as 0
+         */
+        assertEquals(0, callbackResult);
+        assertTrue(handleResult);
+    }
+
+    @Test
+    public void handleGiveDeviceVendorId_success() {
+        mSrcAddr = ADDR_UNREGISTERED;
+        mDesAddr = ADDR_BROADCAST;
+        /** nativeGetVendorId returns 0 */
+        param = new byte[] {
+            (byte) ((0 >> 8) & 0xFF),
+            (byte) (0 & 0xFF),
+            (byte) (0 & 0xFF)
+        };
+        callbackResult = -1;
+        mHdmiLocalDevice.handleGiveDeviceVendorId(
+            (int finalResult) -> callbackResult = finalResult);
+        mTestLooper.dispatchAll();
+        assertEquals(0, callbackResult);
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
index 142b950..94e02bc 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
+++ b/services/tests/servicestests/src/com/android/server/locksettings/SyntheticPasswordTests.java
@@ -448,6 +448,39 @@
         assertTrue(mLocalService.isEscrowTokenActive(handle, PRIMARY_USER_ID));
     }
 
+    public void testgetHashFactorPrimaryUser() throws RemoteException {
+        final String password = "password";
+        mService.setLockCredential(password, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+        final byte[] hashFactor = mService.getHashFactor(password, PRIMARY_USER_ID);
+        assertNotNull(hashFactor);
+
+        mService.setLockCredential(null, LockPatternUtils.CREDENTIAL_TYPE_NONE, password,
+                PASSWORD_QUALITY_UNSPECIFIED, PRIMARY_USER_ID);
+        final byte[] newHashFactor = mService.getHashFactor(null, PRIMARY_USER_ID);
+        assertNotNull(newHashFactor);
+        // Hash factor should never change after password change/removal
+        assertArrayEquals(hashFactor, newHashFactor);
+    }
+
+    public void testgetHashFactorManagedProfileUnifiedChallenge() throws RemoteException {
+        final String pattern = "1236";
+        mService.setLockCredential(pattern, LockPatternUtils.CREDENTIAL_TYPE_PATTERN, null,
+                PASSWORD_QUALITY_SOMETHING, PRIMARY_USER_ID);
+        mService.setSeparateProfileChallengeEnabled(MANAGED_PROFILE_USER_ID, false, null);
+        assertNotNull(mService.getHashFactor(null, MANAGED_PROFILE_USER_ID));
+    }
+
+    public void testgetHashFactorManagedProfileSeparateChallenge() throws RemoteException {
+        final String primaryPassword = "primary";
+        final String profilePassword = "profile";
+        mService.setLockCredential(primaryPassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+                PASSWORD_QUALITY_ALPHABETIC, PRIMARY_USER_ID);
+        mService.setLockCredential(profilePassword, LockPatternUtils.CREDENTIAL_TYPE_PASSWORD, null,
+                PASSWORD_QUALITY_ALPHABETIC, MANAGED_PROFILE_USER_ID);
+        assertNotNull(mService.getHashFactor(profilePassword, MANAGED_PROFILE_USER_ID));
+    }
+
     public void testPasswordData_serializeDeserialize() {
         PasswordData data = new PasswordData();
         data.scryptN = 11;
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/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index dd9a8ab..7bcb571 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -170,6 +170,31 @@
     }
 
     @MediumTest
+    public void testSetUserAdmin() throws Exception {
+        UserInfo userInfo = createUser("SecondaryUser", /*flags=*/ 0);
+
+        // Assert user is not admin and has SMS and calls restrictions.
+        assertFalse(userInfo.isAdmin());
+        assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS,
+                userInfo.getUserHandle()));
+        assertTrue(mUserManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
+                userInfo.getUserHandle()));
+
+        // Assign admin privileges.
+        mUserManager.setUserAdmin(userInfo.id);
+
+        // Refresh.
+        userInfo = mUserManager.getUserInfo(userInfo.id);
+
+        // Verify user became admin and SMS and call restrictions are lifted.
+        assertTrue(userInfo.isAdmin());
+        assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_SMS,
+                userInfo.getUserHandle()));
+        assertFalse(mUserManager.hasUserRestriction(UserManager.DISALLOW_OUTGOING_CALLS,
+                userInfo.getUserHandle()));
+    }
+
+    @MediumTest
     public void testGetProfileParent() throws Exception {
         final int primaryUserId = mUserManager.getPrimaryUser().id;
 
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/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
index 845095a..ac196f9 100644
--- a/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/DisplayContentTests.java
@@ -329,6 +329,21 @@
         assertEquals(window1, sWm.mRoot.computeFocusedWindow());
     }
 
+    @Test
+    public void testKeyguard_preventsSecondaryDisplayFocus() throws Exception {
+        final WindowState keyguard = createWindow(null, TYPE_STATUS_BAR,
+                sWm.getDefaultDisplayContentLocked(), "keyguard");
+        assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
+
+        // Add a window to a second display, and it should be focused
+        final DisplayContent dc = createNewDisplay();
+        final WindowState win = createWindow(null, TYPE_BASE_APPLICATION, dc, "win");
+        assertEquals(win, sWm.mRoot.computeFocusedWindow());
+
+        mWmRule.getWindowManagerPolicy().keyguardShowingAndNotOccluded = true;
+        assertEquals(keyguard, sWm.mRoot.computeFocusedWindow());
+    }
+
     /**
      * This tests setting the maximum ui width on a display.
      */
diff --git a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
index 7bf7dd7..4447b26 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TaskPositionerTests.java
@@ -16,6 +16,7 @@
 
 package com.android.server.wm;
 
+import android.app.IActivityManager;
 import org.junit.Before;
 import org.junit.Ignore;
 import org.junit.Test;
@@ -27,7 +28,10 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.view.Display;
+import org.mockito.Mockito;
 
+import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
+import static android.view.WindowManager.LayoutParams.TYPE_BASE_APPLICATION;
 import static com.android.server.wm.TaskPositioner.MIN_ASPECT;
 import static com.android.server.wm.WindowManagerService.dipToPixel;
 import static com.android.server.wm.WindowState.MINIMUM_VISIBLE_HEIGHT_IN_DP;
@@ -54,6 +58,8 @@
     private int mMinVisibleWidth;
     private int mMinVisibleHeight;
     private TaskPositioner mPositioner;
+    private WindowState mWindow;
+    private Rect mDimBounds = new Rect();
 
     @Before
     public void setUp() throws Exception {
@@ -69,8 +75,20 @@
         mMinVisibleWidth = dipToPixel(MINIMUM_VISIBLE_WIDTH_IN_DP, dm);
         mMinVisibleHeight = dipToPixel(MINIMUM_VISIBLE_HEIGHT_IN_DP, dm);
 
-        mPositioner = TaskPositioner.create(sWm);
+        mPositioner = new TaskPositioner(sWm, Mockito.mock(IActivityManager.class));
         mPositioner.register(mDisplayContent);
+
+        mWindow = Mockito.spy(createWindow(null, TYPE_BASE_APPLICATION, "window"));
+        final Task task = Mockito.spy(mWindow.getTask());
+        Mockito.when(mWindow.getTask()).thenReturn(task);
+
+        Mockito.doAnswer(invocation -> {
+            final Rect rect = (Rect) invocation.getArguments()[0];
+            rect.set(mDimBounds);
+            return (Void) null;
+        }).when(task).getDimBounds(Mockito.any(Rect.class));
+
+        mWindow.getStack().setWindowingMode(WINDOWING_MODE_FREEFORM);
     }
 
     @Test
@@ -94,14 +112,14 @@
      * as does some basic tests (e.g. dragging in Y only will keep X stable).
      */
     @Test
-    @Ignore
     public void testBasicFreeWindowResizing() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
+        mDimBounds.set(r);
 
         // Start a drag resize starting upper left.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -127,8 +145,8 @@
                 mPositioner.getWindowDragBounds());
 
         // Start a drag resize left and see that only the left coord changes..
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -155,15 +173,15 @@
      * This tests that by dragging any edge, the fixed / opposite edge(s) remains anchored.
      */
     @Test
-    @Ignore
     public void testFreeWindowResizingTestAllEdges() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
         final int midY = (r.top + r.bottom) / 2;
+        mDimBounds.set(r);
 
         // Drag upper left.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, 0.0f);
         assertTrue(r.left != mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -171,8 +189,8 @@
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag upper.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -180,8 +198,8 @@
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag upper right.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertTrue(r.right != mPositioner.getWindowDragBounds().right);
@@ -189,8 +207,8 @@
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag right.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.right + MOUSE_DELTA_X, midY);
         mPositioner.resizeDrag(r.right + 100, 0.0f);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertTrue(r.right != mPositioner.getWindowDragBounds().right);
@@ -198,9 +216,9 @@
         assertEquals(r.bottom, mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom right.
-        mPositioner.startDrag(true /*resizing*/,
+        mPositioner.startDrag(mWindow, true /*resizing*/,
                 false /*preserveOrientation*/,
-                r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y, r);
+                r.right + MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertTrue(r.right != mPositioner.getWindowDragBounds().right);
@@ -208,8 +226,8 @@
         assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, midX, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(r.right + 100, r.bottom + 100);
         assertEquals(r.left, mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -217,8 +235,8 @@
         assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
 
         // Drag bottom left.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.bottom + MOUSE_DELTA_Y);
         mPositioner.resizeDrag(0.0f, r.bottom + 100);
         assertTrue(r.left != mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -226,8 +244,8 @@
         assertTrue(r.bottom != mPositioner.getWindowDragBounds().bottom);
 
         // Drag left.
-        mPositioner.startDrag(true /*resizing*/,
-                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                false /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midX);
         mPositioner.resizeDrag(0.0f, r.bottom + 100);
         assertTrue(r.left != mPositioner.getWindowDragBounds().left);
         assertEquals(r.right, mPositioner.getWindowDragBounds().right);
@@ -240,12 +258,12 @@
      * right things upon resizing when dragged from the top left corner.
      */
     @Test
-    @Ignore
     public void testLandscapePreservedWindowResizingDragTopLeft() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
+        mDimBounds.set(r);
 
-        mPositioner.startDrag(true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -278,13 +296,13 @@
      * right things upon resizing when dragged from the left corner.
      */
     @Test
-    @Ignore
     public void testLandscapePreservedWindowResizingDragLeft() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midY = (r.top + r.bottom) / 2;
+        mDimBounds.set(r);
 
-        mPositioner.startDrag(true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -319,13 +337,13 @@
      * right things upon resizing when dragged from the top corner.
      */
     @Test
-    @Ignore
     public void testLandscapePreservedWindowResizingDragTop() throws Exception {
         final Rect r = new Rect(100, 220, 700, 520);
         final int midX = (r.left + r.right) / 2;
+        mDimBounds.set(r);
 
-        mPositioner.startDrag(true /*resizing*/,
-                true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
 
         // Drag to the left (no change).
         mPositioner.resizeDrag(0.0f, r.top);
@@ -356,12 +374,12 @@
      * right things upon resizing when dragged from the top left corner.
      */
     @Test
-    @Ignore
     public void testPortraitPreservedWindowResizingDragTopLeft() throws Exception {
         final Rect r = new Rect(330, 100, 630, 600);
+        mDimBounds.set(r);
 
-        mPositioner.startDrag(true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, r.top - MOUSE_DELTA_Y);
         assertBoundsEquals(r, mPositioner.getWindowDragBounds());
 
         // Drag to a good landscape size.
@@ -371,8 +389,8 @@
                 mPositioner.getWindowDragBounds());
 
         // Drag to a good portrait size.
-        mPositioner.resizeDrag(500.0f, 0.0f);
-        assertBoundsEquals(new Rect(500 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
+        mPositioner.resizeDrag(400.0f, 0.0f);
+        assertBoundsEquals(new Rect(400 + MOUSE_DELTA_X, MOUSE_DELTA_Y, r.right, r.bottom),
                 mPositioner.getWindowDragBounds());
 
         // Drag to a too small size for the height and the the width shrinking.
@@ -389,13 +407,13 @@
      * right things upon resizing when dragged from the left corner.
      */
     @Test
-    @Ignore
     public void testPortraitPreservedWindowResizingDragLeft() throws Exception {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midY = (r.top + r.bottom) / 2;
+        mDimBounds.set(r);
 
-        mPositioner.startDrag(true /*resizing*/,
-                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                true /*preserveOrientation*/, r.left - MOUSE_DELTA_X, midY);
 
         // Drag to the left.
         mPositioner.resizeDrag(0.0f, midY);
@@ -432,13 +450,13 @@
      * right things upon resizing when dragged from the top corner.
      */
     @Test
-    @Ignore
     public void testPortraitPreservedWindowResizingDragTop() throws Exception {
         final Rect r = new Rect(330, 100, 630, 600);
         final int midX = (r.left + r.right) / 2;
+        mDimBounds.set(r);
 
-        mPositioner.startDrag(true /*resizing*/,
-                true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y, r);
+        mPositioner.startDrag(mWindow, true /*resizing*/,
+                true /*preserveOrientation*/, midX, r.top - MOUSE_DELTA_Y);
 
         // Drag to the left (no change).
         mPositioner.resizeDrag(0.0f, r.top);
@@ -472,9 +490,9 @@
                         + ") " + Log.getStackTraceString(new Throwable()));
             }
         }
-        assertEquals(expected.left, actual.left);
-        assertEquals(expected.right, actual.right);
-        assertEquals(expected.top, actual.top);
-        assertEquals(expected.bottom, actual.bottom);
+        assertEquals("left", expected.left, actual.left);
+        assertEquals("right", expected.right, actual.right);
+        assertEquals("top", expected.top, actual.top);
+        assertEquals("bottom", expected.bottom, actual.bottom);
     }
 }
diff --git a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
index 765b3d5..50f3fbe 100644
--- a/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
+++ b/services/tests/servicestests/src/com/android/server/wm/TestWindowManagerPolicy.java
@@ -51,6 +51,7 @@
     private final Supplier<WindowManagerService> mWmSupplier;
 
     int rotationToReport = 0;
+    boolean keyguardShowingAndNotOccluded = false;
 
     private Runnable mRunnableWhenAddingSplashScreen;
 
@@ -338,7 +339,7 @@
 
     @Override
     public boolean isKeyguardLocked() {
-        return false;
+        return keyguardShowingAndNotOccluded;
     }
 
     @Override
@@ -358,7 +359,7 @@
 
     @Override
     public boolean isKeyguardShowingAndNotOccluded() {
-        return false;
+        return keyguardShowingAndNotOccluded;
     }
 
     @Override
diff --git a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
index 32bfda32..d91079e 100644
--- a/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
+++ b/services/tests/servicestests/src/com/android/server/wm/WindowManagerServiceRule.java
@@ -59,6 +59,7 @@
 public class WindowManagerServiceRule implements TestRule {
 
     private WindowManagerService mService;
+    private TestWindowManagerPolicy mPolicy;
 
     @Override
     public Statement apply(Statement base, Description description) {
@@ -108,7 +109,7 @@
                 }
 
                 mService = WindowManagerService.main(context, ims, true, false,
-                        false, new TestWindowManagerPolicy(
+                        false, mPolicy = new TestWindowManagerPolicy(
                                 WindowManagerServiceRule.this::getWindowManagerService));
 
                 mService.onInitReady();
@@ -132,6 +133,7 @@
                 waitUntilWindowManagerHandlersIdle();
                 removeServices();
                 mService = null;
+                mPolicy = null;
             }
         };
     }
@@ -140,6 +142,10 @@
         return mService;
     }
 
+    public TestWindowManagerPolicy getWindowManagerPolicy() {
+        return mPolicy;
+    }
+
     public void waitUntilWindowManagerHandlersIdle() {
         final WindowManagerService wm = getWindowManagerService();
         if (wm != null) {
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index ebc432b..1a38385 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -91,10 +91,12 @@
 import android.os.Bundle;
 import android.os.IBinder;
 import android.os.Process;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.provider.MediaStore;
 import android.provider.Settings.Secure;
 import android.service.notification.Adjustment;
+import android.service.notification.INotificationListener;
 import android.service.notification.NotificationListenerService;
 import android.service.notification.NotificationStats;
 import android.service.notification.NotifyingApp;
@@ -161,6 +163,8 @@
     @Mock
     private NotificationUsageStats mUsageStats;
     @Mock
+    private UsageStatsManagerInternal mAppUsageStats;
+    @Mock
     private AudioManager mAudioManager;
     @Mock
     ActivityManager mActivityManager;
@@ -277,7 +281,7 @@
                     mPackageManager, mPackageManagerClient, mockLightsManager,
                     mListeners, mAssistants, mConditionProviders,
                     mCompanionMgr, mSnoozeHelper, mUsageStats, mPolicyFile, mActivityManager,
-                    mGroupHelper, mAm, mock(UsageStatsManagerInternal.class),
+                    mGroupHelper, mAm, mAppUsageStats,
                     mock(DevicePolicyManagerInternal.class));
         } catch (SecurityException e) {
             if (!e.getMessage().contains("Permission Denial: not allowed to send broadcast")) {
@@ -3041,4 +3045,46 @@
 
         assertEquals(true, mService.canUseManagedServices("d"));
     }
+
+    @Test
+    public void testOnNotificationVisibilityChanged_triggersInterruptionUsageStat() {
+        final NotificationRecord r = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        r.setTextChanged(true);
+        mService.addNotification(r);
+
+        mService.mNotificationDelegate.onNotificationVisibilityChanged(new NotificationVisibility[]
+                {NotificationVisibility.obtain(r.getKey(), 1, 1, true)},
+                new NotificationVisibility[]{});
+
+        verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
+    }
+
+    @Test
+    public void testSetNotificationsShownFromListener_triggersInterruptionUsageStat()
+            throws RemoteException {
+        final NotificationRecord r = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        r.setTextChanged(true);
+        mService.addNotification(r);
+
+        mBinderService.setNotificationsShownFromListener(null, new String[] {r.getKey()});
+
+        verify(mAppUsageStats).reportInterruptiveNotification(anyString(), anyString(), anyInt());
+    }
+
+    @Test
+    public void testMybeRecordInterruptionLocked_doesNotRecordTwice()
+            throws RemoteException {
+        final NotificationRecord r = generateNotificationRecord(
+                mTestNotificationChannel, 1, null, true);
+        r.setInterruptive(true);
+        mService.addNotification(r);
+
+        mService.maybeRecordInterruptionLocked(r);
+        mService.maybeRecordInterruptionLocked(r);
+
+        verify(mAppUsageStats, times(1)).reportInterruptiveNotification(
+                anyString(), anyString(), anyInt());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index e3289ab..c1868e7 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -602,4 +602,45 @@
         record.setIsAppImportanceLocked(false);
         assertEquals(false, record.getIsAppImportanceLocked());
     }
+
+    @Test
+    public void testIsInterruptive_textChanged_notSeen() {
+        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+                false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(false, record.isInterruptive());
+
+        record.setTextChanged(true);
+        assertEquals(false, record.isInterruptive());
+    }
+
+    @Test
+    public void testIsInterruptive_textChanged_seen() {
+        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+                false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(false, record.isInterruptive());
+
+        record.setTextChanged(true);
+        record.setSeen();
+        assertEquals(true, record.isInterruptive());
+    }
+
+    @Test
+    public void testIsInterruptive_textNotChanged_seen() {
+        StatusBarNotification sbn = getNotification(false /*preO */, false /* noisy */,
+                false /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, null /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertEquals(false, record.isInterruptive());
+
+        record.setTextChanged(false);
+        record.setSeen();
+        assertEquals(false, record.isInterruptive());
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
new file mode 100644
index 0000000..c6aea88
--- /dev/null
+++ b/services/tests/uiservicestests/src/com/android/server/slice/PackageMatchingCacheTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.
+ */
+
+package com.android.server.slice;
+
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.support.test.filters.SmallTest;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
+
+import com.android.server.UiServiceTestCase;
+import com.android.server.slice.SliceManagerService.PackageMatchingCache;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.util.function.Supplier;
+
+@SmallTest
+@RunWith(AndroidTestingRunner.class)
+@RunWithLooper
+public class PackageMatchingCacheTest extends UiServiceTestCase {
+
+    private final Supplier<String> supplier = mock(Supplier.class);
+    private final PackageMatchingCache cache = new PackageMatchingCache(supplier);
+
+    @Test
+    public void testNulls() {
+        // Doesn't get for a null input
+        cache.matches(null);
+        verify(supplier, never()).get();
+
+        // Gets once valid input in sent.
+        cache.matches("");
+        verify(supplier).get();
+    }
+
+    @Test
+    public void testCaching() {
+        when(supplier.get()).thenReturn("ret.pkg");
+
+        assertTrue(cache.matches("ret.pkg"));
+        assertTrue(cache.matches("ret.pkg"));
+        assertTrue(cache.matches("ret.pkg"));
+
+        verify(supplier, times(1)).get();
+    }
+
+    @Test
+    public void testGetOnFailure() {
+        when(supplier.get()).thenReturn("ret.pkg");
+        assertTrue(cache.matches("ret.pkg"));
+
+        when(supplier.get()).thenReturn("other.pkg");
+        assertTrue(cache.matches("other.pkg"));
+        verify(supplier, times(2)).get();
+    }
+}
diff --git a/services/usage/java/com/android/server/usage/AppIdleHistory.java b/services/usage/java/com/android/server/usage/AppIdleHistory.java
index 271f813..4e99732 100644
--- a/services/usage/java/com/android/server/usage/AppIdleHistory.java
+++ b/services/usage/java/com/android/server/usage/AppIdleHistory.java
@@ -340,15 +340,27 @@
 
     public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
             int bucket, int reason) {
+        setAppStandbyBucket(packageName, userId, elapsedRealtime, bucket, reason, false);
+    }
+
+    public void setAppStandbyBucket(String packageName, int userId, long elapsedRealtime,
+            int bucket, int reason, boolean resetTimeout) {
         ArrayMap<String, AppUsageHistory> userHistory = getUserHistory(userId);
         AppUsageHistory appUsageHistory =
                 getPackageHistory(userHistory, packageName, elapsedRealtime, true);
         appUsageHistory.currentBucket = bucket;
         appUsageHistory.bucketingReason = reason;
+
+        final long elapsed = getElapsedTime(elapsedRealtime);
+
         if ((reason & REASON_MAIN_MASK) == REASON_MAIN_PREDICTED) {
-            appUsageHistory.lastPredictedTime = getElapsedTime(elapsedRealtime);
+            appUsageHistory.lastPredictedTime = elapsed;
             appUsageHistory.lastPredictedBucket = bucket;
         }
+        if (resetTimeout) {
+            appUsageHistory.bucketActiveTimeoutTime = elapsed;
+            appUsageHistory.bucketWorkingSetTimeoutTime = elapsed;
+        }
         if (DEBUG) {
             Slog.d(TAG, "Moved " + packageName + " to bucket=" + appUsageHistory.currentBucket
                     + ", reason=0x0" + Integer.toHexString(appUsageHistory.bucketingReason));
diff --git a/services/usage/java/com/android/server/usage/AppStandbyController.java b/services/usage/java/com/android/server/usage/AppStandbyController.java
index 08b0496..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;
@@ -113,6 +115,9 @@
 
 /**
  * Manages the standby state of an app, listening to various events.
+ *
+ * Unit test:
+   atest ${ANDROID_BUILD_TOP}/frameworks/base/services/tests/servicestests/src/com/android/server/usage/AppStandbyControllerTests.java
  */
 public class AppStandbyController {
 
@@ -191,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;
@@ -210,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  */
@@ -390,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;
 
@@ -399,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);
         }
@@ -1106,6 +1155,11 @@
 
     void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
             int reason, long elapsedRealtime) {
+        setAppStandbyBucket(packageName, userId, newBucket, reason, elapsedRealtime, false);
+    }
+
+    void setAppStandbyBucket(String packageName, int userId, @StandbyBuckets int newBucket,
+            int reason, long elapsedRealtime, boolean resetTimeout) {
         synchronized (mAppIdleLock) {
             AppIdleHistory.AppUsageHistory app = mAppIdleHistory.getAppUsageHistory(packageName,
                     userId, elapsedRealtime);
@@ -1155,7 +1209,7 @@
             }
 
             mAppIdleHistory.setAppStandbyBucket(packageName, userId, elapsedRealtime, newBucket,
-                    reason);
+                    reason, resetTimeout);
         }
         maybeInformListeners(packageName, userId, elapsedRealtime, newBucket, reason, false);
     }
@@ -1357,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();
@@ -1393,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);
@@ -1421,6 +1490,7 @@
         private IBatteryStats mBatteryStats;
         private PackageManagerInternal mPackageManagerInternal;
         private DisplayManager mDisplayManager;
+        private PowerManager mPowerManager;
         int mBootPhase;
 
         Injector(Context context, Looper looper) {
@@ -1445,6 +1515,7 @@
                 mPackageManagerInternal = LocalServices.getService(PackageManagerInternal.class);
                 mDisplayManager = (DisplayManager) mContext.getSystemService(
                         Context.DISPLAY_SERVICE);
+                mPowerManager = mContext.getSystemService(PowerManager.class);
             }
             mBootPhase = phase;
         }
@@ -1524,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 {
@@ -1587,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;
@@ -1676,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";
@@ -1685,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(',');
@@ -1770,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 71f9bb3..16f8fba 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsService.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsService.java
@@ -900,6 +900,7 @@
             } catch (RemoteException re) {
                 throw re.rethrowFromSystemServer();
             }
+            final boolean shellCaller = callingUid == 0 || callingUid == Process.SHELL_UID;
             final boolean systemCaller = UserHandle.isCore(callingUid);
             final int reason = systemCaller
                     ? UsageStatsManager.REASON_MAIN_FORCED
@@ -918,7 +919,7 @@
                                     + ")");
                 }
                 mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
-                        SystemClock.elapsedRealtime());
+                        SystemClock.elapsedRealtime(), shellCaller);
             } finally {
                 Binder.restoreCallingIdentity(token);
             }
@@ -985,7 +986,7 @@
                         throw new IllegalArgumentException("Cannot set your own standby bucket");
                     }
                     mAppStandby.setAppStandbyBucket(packageName, userId, bucket, reason,
-                            elapsedRealtime);
+                            elapsedRealtime, shellCaller);
                 }
             } finally {
                 Binder.restoreCallingIdentity(token);
@@ -1304,6 +1305,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;
             }
diff --git a/tests/ActivityTests/Android.mk b/tests/ActivityTests/Android.mk
index 61dbcc3..4c68c8b 100644
--- a/tests/ActivityTests/Android.mk
+++ b/tests/ActivityTests/Android.mk
@@ -9,9 +9,10 @@
 LOCAL_MODULE_TAGS := tests
 LOCAL_CERTIFICATE := platform
 
-# Disable AAPT2 to fix:
+LOCAL_USE_AAPT2 := true
+# Disable AAPT2 manifest checks to fix:
 # frameworks/base/tests/ActivityTests/AndroidManifest.xml:42: error: unexpected element <preferred> found in <manifest><application><activity>.
-# TODO(b/79755007): Re-enable AAPT2 when it supports the missing features.
-LOCAL_USE_AAPT2 := false
+# TODO(b/79755007): Remove when AAPT2 recognizes the manifest elements.
+LOCAL_AAPT_FLAGS += --warn-manifest-validation
 
 include $(BUILD_PACKAGE)
diff --git a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
index 6ce66f0..4a6fe49 100644
--- a/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
+++ b/tests/AppLaunch/src/com/android/tests/applaunch/AppLaunch.java
@@ -184,7 +184,8 @@
         if (null != launchDirectory && !launchDirectory.isEmpty()) {
             launchRootDir = new File(launchDirectory);
             if (!launchRootDir.exists() && !launchRootDir.mkdirs()) {
-                throw new IOException("Unable to create the destination directory");
+                throw new IOException("Unable to create the destination directory "
+                    + launchRootDir + ". Try disabling selinux.");
             }
         }
 
@@ -192,7 +193,8 @@
             File launchSubDir = new File(launchRootDir, LAUNCH_SUB_DIRECTORY);
 
             if (!launchSubDir.exists() && !launchSubDir.mkdirs()) {
-                throw new IOException("Unable to create the lauch file sub directory");
+                throw new IOException("Unable to create the lauch file sub directory "
+                    + launchSubDir + ". Try disabling selinux.");
             }
             File file = new File(launchSubDir, LAUNCH_FILE);
             FileOutputStream outputStream = new FileOutputStream(file);
@@ -769,6 +771,8 @@
                              BufferedWriter writer =
                                 new BufferedWriter(new OutputStreamWriter(stream))) {
                             String cmd = String.format(SIMPLEPERF_APP_CMD, packageName, launchCmd);
+                            // In the file, we need to escape any "$".
+                            cmd = cmd.replace("$", "\\$");
                             writer.write(cmd);
                         }
                         launchCmd = launchFile.getAbsolutePath();
diff --git a/tests/net/java/android/net/apf/ApfTest.java b/tests/net/java/android/net/apf/ApfTest.java
index ed9cbab..0248e97 100644
--- a/tests/net/java/android/net/apf/ApfTest.java
+++ b/tests/net/java/android/net/apf/ApfTest.java
@@ -77,7 +77,7 @@
 @SmallTest
 public class ApfTest {
     private static final int TIMEOUT_MS = 500;
-    private final static int MIN_APF_VERSION = 2;
+    private static final int MIN_APF_VERSION = 2;
 
     @Mock IpConnectivityLog mLog;
     @Mock Context mContext;
@@ -90,20 +90,30 @@
     }
 
     // Expected return codes from APF interpreter.
-    private final static int PASS = 1;
-    private final static int DROP = 0;
+    private static final int PASS = 1;
+    private static final int DROP = 0;
     // Interpreter will just accept packets without link layer headers, so pad fake packet to at
     // least the minimum packet size.
-    private final static int MIN_PKT_SIZE = 15;
+    private static final int MIN_PKT_SIZE = 15;
 
     private static final ApfCapabilities MOCK_APF_CAPABILITIES =
       new ApfCapabilities(2, 1700, ARPHRD_ETHER);
 
-    private final static boolean DROP_MULTICAST = true;
-    private final static boolean ALLOW_MULTICAST = false;
+    private static final boolean DROP_MULTICAST = true;
+    private static final boolean ALLOW_MULTICAST = false;
 
-    private final static boolean DROP_802_3_FRAMES = true;
-    private final static boolean ALLOW_802_3_FRAMES = false;
+    private static final boolean DROP_802_3_FRAMES = true;
+    private static final boolean ALLOW_802_3_FRAMES = false;
+
+    // Constants for opcode encoding
+    private static final byte LI_OP   = (byte)(13 << 3);
+    private static final byte LDDW_OP = (byte)(22 << 3);
+    private static final byte STDW_OP = (byte)(23 << 3);
+    private static final byte SIZE0   = (byte)(0 << 1);
+    private static final byte SIZE8   = (byte)(1 << 1);
+    private static final byte SIZE16  = (byte)(2 << 1);
+    private static final byte SIZE32  = (byte)(3 << 1);
+    private static final byte R1 = 1;
 
     private static ApfConfiguration getDefaultConfig() {
         ApfFilter.ApfConfiguration config = new ApfConfiguration();
@@ -636,29 +646,28 @@
      */
     @Test
     public void testImmediateEncoding() throws IllegalInstructionException {
-        final int LI_OPCODE = 13 << 3;
         ApfGenerator gen;
 
         // 0-byte immediate: li R0, 0
-        gen = new ApfGenerator(3);
+        gen = new ApfGenerator(4);
         gen.addLoadImmediate(Register.R0, 0);
-        assertProgramEquals(new byte[]{LI_OPCODE | (0 << 1)}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE0}, gen.generate());
 
         // 1-byte immediate: li R0, 42
-        gen = new ApfGenerator(3);
+        gen = new ApfGenerator(4);
         gen.addLoadImmediate(Register.R0, 42);
-        assertProgramEquals(new byte[]{LI_OPCODE | (1 << 1), 42}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE8, 42}, gen.generate());
 
         // 2-byte immediate: li R1, 0x1234
-        gen = new ApfGenerator(3);
+        gen = new ApfGenerator(4);
         gen.addLoadImmediate(Register.R1, 0x1234);
-        assertProgramEquals(new byte[]{LI_OPCODE | (2 << 1) | 1 , 0x12, 0x34}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, 0x12, 0x34}, gen.generate());
 
         // 4-byte immediate: li R0, 0x12345678
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R0, 0x12345678);
         assertProgramEquals(
-                new byte[]{LI_OPCODE | (3 << 1), 0x12, 0x34, 0x56, 0x78},
+                new byte[]{LI_OP | SIZE32, 0x12, 0x34, 0x56, 0x78},
                 gen.generate());
     }
 
@@ -667,28 +676,61 @@
      */
     @Test
     public void testNegativeImmediateEncoding() throws IllegalInstructionException {
-        final int LI_OPCODE = 13 << 3;
         ApfGenerator gen;
 
         // 1-byte negative immediate: li R0, -42
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R0, -42);
-        assertProgramEquals(new byte[]{LI_OPCODE | (1 << 1), -42}, gen.generate());
+        assertProgramEquals(new byte[]{LI_OP | SIZE8, -42}, gen.generate());
 
-        // 2-byte negative immediate: li R1, -0x1234
+        // 2-byte negative immediate: li R1, -0x1122
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R1, -0x1122);
-        assertProgramEquals(new byte[]{LI_OPCODE | (2 << 1) | 1, (byte)0xEE, (byte)0xDE},
+        assertProgramEquals(new byte[]{LI_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
                 gen.generate());
 
         // 4-byte negative immediate: li R0, -0x11223344
         gen = new ApfGenerator(3);
         gen.addLoadImmediate(Register.R0, -0x11223344);
         assertProgramEquals(
-                new byte[]{LI_OPCODE | (3 << 1), (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
+                new byte[]{LI_OP | SIZE32, (byte)0xEE, (byte)0xDD, (byte)0xCC, (byte)0xBC},
                 gen.generate());
     }
 
+    /**
+     * Test that the generator correctly emits positive and negative immediates for LDDW/STDW.
+     */
+    @Test
+    public void testLoadStoreDataEncoding() throws IllegalInstructionException {
+        ApfGenerator gen;
+
+        // Load data with no offset: lddw R0, [0 + r1]
+        gen = new ApfGenerator(3);
+        gen.addLoadData(Register.R0, 0);
+        assertProgramEquals(new byte[]{LDDW_OP | SIZE0}, gen.generate());
+
+        // Store data with 8bit negative offset: lddw r0, [-42 + r1]
+        gen = new ApfGenerator(3);
+        gen.addStoreData(Register.R0, -42);
+        assertProgramEquals(new byte[]{STDW_OP | SIZE8, -42}, gen.generate());
+
+        // Store data to R1 with 16bit negative offset: stdw r1, [-0x1122 + r0]
+        gen = new ApfGenerator(3);
+        gen.addStoreData(Register.R1, -0x1122);
+        assertProgramEquals(new byte[]{STDW_OP | SIZE16 | R1, (byte)0xEE, (byte)0xDE},
+                gen.generate());
+
+        // Load data to R1 with 32bit negative offset: lddw r1, [0xDEADBEEF + r0]
+        gen = new ApfGenerator(3);
+        gen.addLoadData(Register.R1, 0xDEADBEEF);
+        assertProgramEquals(
+                new byte[]{LDDW_OP | SIZE32 | R1, (byte)0xDE, (byte)0xAD, (byte)0xBE, (byte)0xEF},
+                gen.generate());
+    }
+
+    /**
+     * Test that the interpreter correctly executes STDW with a negative 8bit offset
+     */
     @Test
     public void testApfDataWrite() throws IllegalInstructionException, Exception {
         byte[] packet = new byte[MIN_PKT_SIZE];
@@ -712,12 +754,15 @@
         assertDataMemoryContents(PASS, gen.generate(), packet, data, expected_data);
     }
 
+    /**
+     * Test that the interpreter correctly executes LDDW with a negative 16bit offset
+     */
     @Test
     public void testApfDataRead() throws IllegalInstructionException, Exception {
         // Program that DROPs if address 10 (-6) contains 0x87654321.
         ApfGenerator gen = new ApfGenerator(3);
-        gen.addLoadImmediate(Register.R1, 10);
-        gen.addLoadData(Register.R0, -16);  // 10 + -16 = -6 (offset +10 with data_len=16)
+        gen.addLoadImmediate(Register.R1, 1000);
+        gen.addLoadData(Register.R0, -1006);  // 1000 + -1006 = -6 (offset +10 with data_len=16)
         gen.addJumpIfR0Equals(0x87654321, gen.DROP_LABEL);
         byte[] program = gen.generate();
         byte[] packet = new byte[MIN_PKT_SIZE];
@@ -737,6 +782,11 @@
         assertDataMemoryContents(DROP, program, packet, data, expected_data);
     }
 
+    /**
+     * Test that the interpreter correctly executes LDDW followed by a STDW.
+     * To cover a few more edge cases, LDDW has a 0bit offset, while STDW has a positive 8bit
+     * offset.
+     */
     @Test
     public void testApfDataReadModifyWrite() throws IllegalInstructionException, Exception {
         ApfGenerator gen = new ApfGenerator(3);
@@ -844,7 +894,7 @@
     }
 
     private static class TestApfFilter extends ApfFilter {
-        public final static byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
+        public static final byte[] MOCK_MAC_ADDR = {1,2,3,4,5,6};
 
         private FileDescriptor mWriteSocket;
         private final long mFixedTimeMs = SystemClock.elapsedRealtime();
diff --git a/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java b/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java
new file mode 100644
index 0000000..40a8b3e
--- /dev/null
+++ b/tests/net/java/android/net/captiveportal/CaptivePortalProbeSpecTest.java
@@ -0,0 +1,171 @@
+/*
+ * 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.
+ */
+
+package android.net.captiveportal;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertNull;
+import static junit.framework.Assert.assertTrue;
+
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.text.ParseException;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class CaptivePortalProbeSpecTest {
+
+    @Test
+    public void testGetResult_Regex() throws MalformedURLException, ParseException {
+        // 2xx status or 404, with an empty (match everything) location regex
+        CaptivePortalProbeSpec statusRegexSpec = CaptivePortalProbeSpec.parseSpec(
+                "http://www.google.com@@/@@2[0-9]{2}|404@@/@@");
+
+        // 404, or 301/302 redirect to some HTTPS page under google.com
+        CaptivePortalProbeSpec redirectSpec = CaptivePortalProbeSpec.parseSpec(
+                "http://google.com@@/@@404|30[12]@@/@@https://([0-9a-z]+\\.)*google\\.com.*");
+
+        assertSuccess(statusRegexSpec.getResult(200, null));
+        assertSuccess(statusRegexSpec.getResult(299, "qwer"));
+        assertSuccess(statusRegexSpec.getResult(404, null));
+        assertSuccess(statusRegexSpec.getResult(404, ""));
+
+        assertPortal(statusRegexSpec.getResult(300, null));
+        assertPortal(statusRegexSpec.getResult(399, "qwer"));
+        assertPortal(statusRegexSpec.getResult(500, null));
+
+        assertSuccess(redirectSpec.getResult(404, null));
+        assertSuccess(redirectSpec.getResult(404, ""));
+        assertSuccess(redirectSpec.getResult(301, "https://www.google.com"));
+        assertSuccess(redirectSpec.getResult(301, "https://www.google.com/test?q=3"));
+        assertSuccess(redirectSpec.getResult(302, "https://google.com/test?q=3"));
+
+        assertPortal(redirectSpec.getResult(299, "https://google.com/test?q=3"));
+        assertPortal(redirectSpec.getResult(299, ""));
+        assertPortal(redirectSpec.getResult(499, null));
+        assertPortal(redirectSpec.getResult(301, "http://login.portal.example.com/loginpage"));
+        assertPortal(redirectSpec.getResult(302, "http://www.google.com/test?q=3"));
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_Empty() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_Null() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec(null);
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_MissingParts() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_TooManyParts() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@456@@/@@extra");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_InvalidStatusRegex() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@unmatched(parenthesis@@/@@456");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_InvalidLocationRegex() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("http://google.com/@@/@@123@@/@@unmatched[[]bracket");
+    }
+
+    @Test(expected = MalformedURLException.class)
+    public void testParseSpec_EmptyURL() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("@@/@@123@@/@@123");
+    }
+
+    @Test(expected = ParseException.class)
+    public void testParseSpec_NoParts() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("invalid");
+    }
+
+    @Test(expected = MalformedURLException.class)
+    public void testParseSpec_RegexInvalidUrl() throws MalformedURLException, ParseException {
+        CaptivePortalProbeSpec.parseSpec("notaurl@@/@@123@@/@@123");
+    }
+
+    @Test
+    public void testParseSpecOrNull_UsesSpec() {
+        final String specUrl = "http://google.com/probe";
+        final String redirectUrl = "https://google.com/probe";
+        CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(
+                specUrl + "@@/@@302@@/@@" + redirectUrl);
+        assertEquals(specUrl, spec.getUrl().toString());
+
+        assertPortal(spec.getResult(302, "http://portal.example.com"));
+        assertSuccess(spec.getResult(302, redirectUrl));
+    }
+
+    @Test
+    public void testParseSpecOrNull_UsesFallback() throws MalformedURLException {
+        CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull(null);
+        assertNull(spec);
+
+        spec = CaptivePortalProbeSpec.parseSpecOrNull("");
+        assertNull(spec);
+
+        spec = CaptivePortalProbeSpec.parseSpecOrNull("@@/@@ @@/@@ @@/@@");
+        assertNull(spec);
+
+        spec = CaptivePortalProbeSpec.parseSpecOrNull("invalid@@/@@123@@/@@456");
+        assertNull(spec);
+    }
+
+    @Test
+    public void testParseSpecOrUseStatusCodeFallback_EmptySpec() throws MalformedURLException {
+        CaptivePortalProbeSpec spec = CaptivePortalProbeSpec.parseSpecOrNull("");
+        assertNull(spec);
+    }
+
+    private void assertIsStatusSpec(CaptivePortalProbeSpec spec) {
+        assertSuccess(spec.getResult(204, null));
+        assertSuccess(spec.getResult(204, "1234"));
+
+        assertPortal(spec.getResult(200, null));
+        assertPortal(spec.getResult(301, null));
+        assertPortal(spec.getResult(302, "1234"));
+        assertPortal(spec.getResult(399, ""));
+
+        assertFailed(spec.getResult(404, null));
+        assertFailed(spec.getResult(500, "1234"));
+    }
+
+    private void assertPortal(CaptivePortalProbeResult result) {
+        assertTrue(result.isPortal());
+    }
+
+    private void assertSuccess(CaptivePortalProbeResult result) {
+        assertTrue(result.isSuccessful());
+    }
+
+    private void assertFailed(CaptivePortalProbeResult result) {
+        assertTrue(result.isFailed());
+    }
+}
diff --git a/tools/aapt2/link/NoDefaultResourceRemover.cpp b/tools/aapt2/link/NoDefaultResourceRemover.cpp
index cfb4b26..5173b85 100644
--- a/tools/aapt2/link/NoDefaultResourceRemover.cpp
+++ b/tools/aapt2/link/NoDefaultResourceRemover.cpp
@@ -22,17 +22,7 @@
 
 namespace aapt {
 
-static bool IsDefaultConfigRequired(const ConfigDescription& config) {
-  // We don't want to be overzealous with resource removal, so have strict requirements.
-  // If a resource defines a value for a locale-only configuration, the default configuration is
-  // required.
-  if (ConfigDescription::DefaultConfig().diff(config) == ConfigDescription::CONFIG_LOCALE) {
-    return true;
-  }
-  return false;
-}
-
-static bool KeepResource(const std::unique_ptr<ResourceEntry>& entry) {
+static bool KeepResource(const std::unique_ptr<ResourceEntry>& entry, int minSdk) {
   if (entry->visibility.level == Visibility::Level::kPublic) {
     // Removing a public API without the developer knowing is bad, so just leave this here for now.
     return true;
@@ -44,22 +34,44 @@
   }
 
   // There is no default value defined, check if removal is required.
+  bool defaultRequired = false;
   for (const auto& config_value : entry->values) {
-    if (IsDefaultConfigRequired(config_value->config)) {
-      return false;
+    const int config = ConfigDescription::DefaultConfig().diff(config_value->config);
+    // If a resource defines a value for a locale-only configuration, the default configuration is
+    // required.
+    if (config == ConfigDescription::CONFIG_LOCALE) {
+      defaultRequired = true;
+    }
+    // If a resource defines a version-only config, the config value can be used as a default if
+    // the version is at most the minimum sdk version
+    else if (config == ConfigDescription::CONFIG_VERSION
+        && config_value->config.sdkVersion <= minSdk) {
+      return true;
+    }
+    // If a resource defines a value for a density only configuration, then that value could be used
+    // as a default and the entry should not be removed
+    else if (config == ConfigDescription::CONFIG_DENSITY
+        || (config == (ConfigDescription::CONFIG_DENSITY | ConfigDescription::CONFIG_VERSION)
+            && config_value->config.sdkVersion <= minSdk)) {
+      return true;
     }
   }
-  return true;
+
+  return !defaultRequired;
 }
 
 bool NoDefaultResourceRemover::Consume(IAaptContext* context, ResourceTable* table) {
-  const ConfigDescription default_config = ConfigDescription::DefaultConfig();
   for (auto& pkg : table->packages) {
     for (auto& type : pkg->types) {
+      // Gather the entries without defaults that must be removed
+      const int minSdk = context->GetMinSdkVersion();
       const auto end_iter = type->entries.end();
-      const auto new_end_iter =
-          std::stable_partition(type->entries.begin(), end_iter, KeepResource);
-      for (auto iter = new_end_iter; iter != end_iter; ++iter) {
+      const auto remove_iter = std::stable_partition(type->entries.begin(), end_iter,
+          [&minSdk](const std::unique_ptr<ResourceEntry>& entry) -> bool {
+        return KeepResource(entry, minSdk);
+      });
+
+      for (auto iter = remove_iter; iter != end_iter; ++iter) {
         const ResourceName name(pkg->name, type->type, (*iter)->name);
         IDiagnostics* diag = context->GetDiagnostics();
         diag->Warn(DiagMessage() << "removing resource " << name
@@ -74,7 +86,7 @@
         }
       }
 
-      type->entries.erase(new_end_iter, type->entries.end());
+      type->entries.erase(remove_iter, end_iter);
     }
   }
   return true;
diff --git a/tools/aapt2/link/NoDefaultResourceRemover_test.cpp b/tools/aapt2/link/NoDefaultResourceRemover_test.cpp
index 943709a..d129c9a 100644
--- a/tools/aapt2/link/NoDefaultResourceRemover_test.cpp
+++ b/tools/aapt2/link/NoDefaultResourceRemover_test.cpp
@@ -46,4 +46,64 @@
   EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:string/baz")));
 }
 
+TEST(NoDefaultResourceRemoverTest, KeepEntryWithLocalesAndDensities) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().SetMinSdkVersion(26).Build();
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("android", 0x01)
+          .AddSimple("android:drawable/keep1", test::ParseConfigOrDie("mdpi")) // v4
+          .AddSimple("android:drawable/keep1", test::ParseConfigOrDie("en-rGB"))
+          .AddSimple("android:drawable/keep1", test::ParseConfigOrDie("fr-rFR"))
+          .AddSimple("android:drawable/keep2", test::ParseConfigOrDie("fr-rFR"))
+          .AddSimple("android:drawable/keep2", test::ParseConfigOrDie("en-rGB"))
+          .AddSimple("android:drawable/keep2", test::ParseConfigOrDie("xxxhdpi")) // v4
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("fr-rFR"))
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("en-rGB"))
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("w600dp-xhdpi")) // v13
+          .Build();
+
+  NoDefaultResourceRemover remover;
+  ASSERT_TRUE(remover.Consume(context.get(), table.get()));
+
+  EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:drawable/keep1")));
+  EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:drawable/keep2")));
+  EXPECT_FALSE(table->FindResource(test::ParseNameOrDie("android:drawable/remove1")));
+}
+
+TEST(NoDefaultResourceRemoverTest, RemoveEntryWithLocalesAndDensitiesLowVersion) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().SetMinSdkVersion(3).Build();
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("android", 0x01)
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("mdpi")) // v4
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("en-rGB"))
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("fr-rFR"))
+          .Build();
+
+  NoDefaultResourceRemover remover;
+  ASSERT_TRUE(remover.Consume(context.get(), table.get()));
+
+  EXPECT_FALSE(table->FindResource(test::ParseNameOrDie("android:drawable/remove1")));
+}
+
+TEST(NoDefaultResourceRemoverTest, KeepEntryWithVersion) {
+  std::unique_ptr<IAaptContext> context = test::ContextBuilder().SetMinSdkVersion(8).Build();
+  std::unique_ptr<ResourceTable> table =
+      test::ResourceTableBuilder()
+          .SetPackageId("android", 0x01)
+          .AddSimple("android:drawable/keep1", test::ParseConfigOrDie("v8"))
+          .AddSimple("android:drawable/keep1", test::ParseConfigOrDie("en-rGB"))
+          .AddSimple("android:drawable/keep1", test::ParseConfigOrDie("fr-rFR"))
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("v9"))
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("en-rGB"))
+          .AddSimple("android:drawable/remove1", test::ParseConfigOrDie("fr-rFR"))
+          .Build();
+
+  NoDefaultResourceRemover remover;
+  ASSERT_TRUE(remover.Consume(context.get(), table.get()));
+
+  EXPECT_TRUE(table->FindResource(test::ParseNameOrDie("android:drawable/keep1")));
+  EXPECT_FALSE(table->FindResource(test::ParseNameOrDie("android:drawable/remove1")));
+}
+
 }  // namespace aapt